테스트 커버리지 높이기¶
Python 개발에서는 언어와 stdlib(표준 라이브러리)에 대한 모든 의미론적 변경 및 추가에 적절한 단위 테스트를 함께 제공하는 관행을 따릅니다. 안타깝게도 이 관행이 시행되기 훨씬 전부터 Python이 존재했습니다. 그 결과 stdlib의 일부가 테스트되지 않은 채 남았으며, 이는 바람직한 상황이 아닙니다.
Python 코드에 익숙해지고 기여하는 쉽고 좋은 방법은 Python stdlib의 테스트 커버리지를 높이는 데 도움을 주는 것입니다. 이상적으로는 커버리지가 100%이기를 바라지만, 조금이라도 높아지는 것은 좋은 일입니다. 하지만 커버리지를 100%로 만드는 것이 항상 가능한 것은 아님을 명심하십시오. 단순히 사용자의 환경에서는 실행되지 않는 플랫폼별 코드나 출력의 오류 등이 있을 수 있습니다. 무엇을 커버해야 하고 무엇을 커버하지 않아도 되는지는 스스로 판단할 수 있지만, 보수적으로 접근하여 어떤 코드든 커버해야 한다고 가정하는 것이 일반적으로 따르기 좋은 원칙입니다.
테스트 커버리지를 높일 모듈을 선택하는 방법에는 몇 가지가 있습니다. 커버리지를 활성화한 상태로 전체 테스트 스위트를 직접 실행하여 어떤 모듈에 도움이 필요한지 확인할 수 있습니다. 이 방법은 커버리지를 측정하면서 전체 테스트 스위트를 실행하므로 완료하는 데 시간이 걸린다는 단점이 있지만, 어떤 모듈에 가장 많은 작업이 필요한지 정확한 최신 정보를 얻을 수 있습니다.
또 다른 방법은 아래 예제를 따라 선호하는 모듈의 커버리지가 어느 정도인지 간단히 확인하는 것입니다. 하지만 이는 “어둠 속에서 찌르기”와 같으므로 커버리지 개선이 필요한 모듈을 찾는 데 시간이 걸릴 수 있습니다.
다만 어떤 모듈을 작업하기로 결정하든 반드시 해당 모듈에 대해서만 커버리지를 실행하십시오. 그러면 우연히 해당 모듈을 사용하는 다른 코드의 암묵적인 테스트가 아니라 모듈 자체의 테스트 세트로 얻은 명시적 커버리지가 얼마나 좋은지 확인할 수 있습니다.
흔히 빠지는 함정¶
커버리지 데이터 기록이 시작되기 전에 이미 임포트된 모듈의 커버리지 보고서는 잘못된다는 점에 유의하십시오. 일반적으로 임포트할 때 분명히 실행되는 전역 문이 실행되지 않은 것으로 나타나는 반면 지역 문은 커버된 것으로 커버리지 보고서에 표시되면 해당 모듈이 이 범주에 속한다는 것을 알 수 있습니다. 이런 경우에는 전역 문의 커버리지를 무시하고 지역 문의 커버리지에만 집중하면 됩니다.
커버리지를 높이기 위해 새 테스트를 작성할 때는 모듈에 이미 제공된 테스트의 스타일(예: 화이트박스, 블랙박스 등)에 유의하십시오. 일부 모듈은 주로 한 명의 코어 개발자가 유지 관리하므로, 해당 개발자는 사용하는 테스트 유형(예: 화이트박스)에 관해 구체적인 선호가 있을 수 있으며 다른 유형의 테스트(예: 블랙박스)는 사용하지 않기를 바랄 수 있습니다. 확신이 없다면 코드를 적절히 실행해 보기 위해 화이트박스 테스트를 사용하십시오.
커버리지 측정¶
Python 자체 stdlib의 커버리지를 측정할 때 나타나는 특이점은 특정 모듈이 인터프리터 시작 과정에서 임포트된다는 것입니다. Python 자체에 필요한 이러한 모듈은 커버리지 도구에서 실행된 것으로 간주되지 않으므로 커버리지가 매우 낮은 것처럼 보입니다(예: stat 모듈). 이런 경우 해당 모듈은 전역 문이 전혀 커버되지 않은 것처럼 보이지만 지역 문은 제대로 커버됩니다(예: 함수 정의는 추적되지 않지만 함수 본문은 추적됩니다). 이 상황에서 모듈의 커버리지를 계산하려면 실행되지 않은 지역 문을 직접 살펴보기만 하면 됩니다.
coverage.py 사용하기¶
가장 널리 사용되는 서드파티 커버리지 도구 중 하나인 coverage.py는 매우 훌륭한 HTML 출력과 분기 커버리지 같은 고급 기능을 제공합니다. stdlib에서 제공하는 도구만 사용하려면 test.regrtest를 사용하십시오.
coverage 설치¶
기본적으로 pip는 방금 빌드한 개발 중인 Python 버전에 설치하지 않으며, 이 빌드된 Python 버전에서는 기본 Python 버전에 설치된 패키지를 인식할 수 없습니다. 한 가지 방법은 가상 환경을 사용하여 coverage를 설치하는 것입니다.
다음을 실행하십시오:
./python -m venv ../cpython-venv
source ../cpython-venv/bin/activate
pip install coverage
관련 대부분의 macOS 시스템에서는 다음을 실행하십시오:
./python.exe -m venv ../cpython-venv
source ../cpython-venv/bin/activate
pip install coverage
다음을 실행하십시오:
python.bat -m venv ..\\cpython-venv
..\\cpython-venv\\Scripts\\activate.bat
pip install coverage
이제 venv가 활성화되어 있는 동안에는 나머지 지침에서 ./ 없이 python을 사용할 수 있습니다. venv에 관한 자세한 내용은 가상 환경 문서를 참조하십시오.
어떤 이유로든 이 방법이 작동하지 않으면 개발 중인 coverage.py 버전을 사용하여 필요에 맞게 업데이트되었는지 확인해 보십시오. 이렇게 하려면 coverage.py의 개발 버전을 클론/체크아웃해야 합니다.:
git clone https://github.com/nedbat/coveragepy
설치 위치의 전체 경로를 사용해야 합니다.
이미 설치된 coverage.py 복사본이 있다면 이를 사용하는 것도 한 가지 방법입니다. 이 경우에도 해당 설치 위치의 전체 경로를 사용해야 합니다.
기본 사용법¶
다음 명령은 사용 중인 coverage 복사본이 작동하는지 알려 줍니다(COVERAGEDIR을 클론이 있는 디렉터리로 바꾸십시오. 예: ../coveragepy).:
./python COVERAGEDIR
Coverage.py는 모든 것이 제대로 작동하는지 확인하는 짧은 도움말 텍스트를 출력합니다. 설치된 복사본을 사용한다면 대신 다음과 같이 할 수 있습니다(이는 venv 등을 통해 빌드된 Python 복사본을 사용하여 설치해야 합니다).:
./python -m coverage
이후의 coverage.py 사용 예제에서는 클론한 복사본을 사용한다고 가정하지만, 위의 방법으로 대체해도 모든 지침은 여전히 유효합니다.
coverage.py에서 테스트 스위트를 실행하려면 다음과 같이 하십시오.:
./python COVERAGEDIR run --pylib Lib/test/regrtest.py
테스트 하나만 실행하려면 --source 플래그에 테스트할 모듈/패키지를 지정하고(관심 있는 모듈/패키지만 커버리지 보고서에 포함되도록 범위를 줄이기 위해), 실행하려는 테스트의 이름을 명령 끝에 추가하십시오.:
./python COVERAGEDIR run --pylib --source=abc Lib/test/regrtest.py test_abc
커버리지 실행 결과를 확인하려면 다음 명령으로 텍스트 기반 보고서를 볼 수 있습니다.:
./python COVERAGEDIR report
실행되지 않은 줄의 목록을 확인하려면 --show-missing 플래그를 사용할 수 있습니다.:
./python COVERAGEDIR report --show-missing
그러나 coverage.py의 장점 중 하나는 테스트되지 않은 코드 줄을 시각적으로 확인할 수 있는 HTML 기반 보고서입니다.:
./python COVERAGEDIR html -i --include=`pwd`/Lib/* --omit="Lib/test/*,Lib/*/tests/*"
이 명령은 발생할 수 있는 모든 오류를 무시하고 테스트 커버리지가 중요하지 않은 모듈(예: 테스트, 임시 파일 등)을 제외한 HTML 보고서를 htmlcov 디렉터리에 생성합니다. 그런 다음 웹 브라우저에서 htmlcov/index.html 파일을 열어 커버리지 결과와 함께 어떤 코드 줄이 실행되었거나 실행되지 않았는지 시각적으로 보여 주는 페이지를 확인할 수 있습니다.
분기 커버리지¶
정말 과감하게 도전하려는 경우 coverage.py의 또 다른 강력한 기능인 분기 커버리지를 사용할 수 있습니다. 코드에서 가능한 모든 분기 경로를 테스트하는 것은 추구할 만한 훌륭한 목표이지만, 현재로서는 전체 표준 라이브러리에서 100% 줄 커버리지를 달성하는 것보다 우선순위가 낮은 목표입니다.
분기 커버리지를 개선하려면 커버리지 실행에 --branch 플래그를 추가하기만 하면 됩니다.:
./python COVERAGEDIR run --pylib --branch <arguments to run test(s)>
그러면 보고서에 커버되지 않은 줄뿐만 아니라 실행되지 않은 분기 경로도 표시됩니다.
test.regrtest 사용하기¶
커버리지 데이터를 생성할 때 표준 라이브러리에만 의존하려면 적절한 플래그를 test에 전달하면 됩니다(원하는 다른 플래그도 함께 전달할 수 있습니다).:
./python -m test --coverage -D `pwd`/coverage_data <test arguments>
-D 인자에 유의하십시오. 커버리지 데이터를 저장할 위치의 절대 경로를 지정하지 않으면 예상하지 못한 위치에 저장됩니다.
참고
전체 테스트 스위트의 커버리지를 실행하는 경우, 커버리지 실행 중 예외를 발생시키는 테스트를 제외하도록 -x test_importlib test_runpy test_trace를 반드시 추가하십시오. python/cpython#54750 및 python/cpython#55200을 참조하십시오.
테스트가 완료되면 지정한 디렉터리에 실행된 각 모듈의 파일과 각 줄이 실행된 횟수에 관한 정보가 포함되어 있음을 확인할 수 있습니다.
이슈 등록¶
커버리지를 높인 후에는 issue tracker에 이슈를 생성하고 pull request를 제출해야 합니다.
gcov와 lcov를 사용한 C 코드의 커버리지 측정¶
Python C 코드의 함수, 줄 및 분기 커버리지도 측정할 수 있습니다. 현재는 gcov를 사용하는 GCC만 지원합니다. gcov로 계측된 Python 빌드를 생성하려면 다음을 실행하십시오:
make coverage
.\make coverage
그런 다음 코드를 실행하고 gcov 명령으로 커버리지 데이터를 수집하십시오. HTML 보고서를 생성하려면 lcov를 설치할 수 있습니다. 다음 명령은:
make coverage-lcov
.\make coverage-lcov
커버리지 데이터를 취합하고, 서드 파티 및 시스템 라이브러리를 제거한 후, 최종적으로 보고서를 생성합니다. 두 단계를 모두 건너뛰고 다음 명령만 실행할 수도 있습니다:
make coverage-report
.\make coverage-report
Python 표준 라이브러리 테스트의 커버리지 보고서를 생성하려는 경우에 사용합니다. 최신 컴퓨터에서는 약 20~30분이 걸립니다.
참고
여러 테스트 작업은 제대로 작동하지 않을 수 있습니다. C 커버리지 보고는 단일 테스트 프로세스에서만 테스트되었습니다.