brunch

매거진 Django doc

You can make anything
by writing

C.S.Lewis

by 장영석 Jan 15. 2020

Writing and running tests

Writing tests

Django 는 unit test 는 Python 의 표준 라이브러리 모듈(unittest)를 사용합니다. 이 모듈은 클래스 기반 접근 방식을 사용하여 테스트를 정의합니다.

아래 예제는 unittest.TestCase의 서브클래스인 django.test.TestCase 의 서브클래스를 사용한 예제입니다. 각 테스트는 트랜잭션 내에서 독립적으로 실행하여 격리를 제공합니다.

테스트를 실행할 때, 테스트 유틸리티의 기본적인 행동은 test 로 시작하는 모든 파일에서 모든 테스트 케이스(unittest.TestCase 의 subclass)를 찾은 후, 자동으로 test suite를 빌드하고 실행하는 것 입니다.


모델을 만들거나 조회하는 것이 데이터베이스에 의존적인 테스트인 경우 unittest.TestCase 보다 django.test.TestCase 를 사용하는 것이 좋습니다. unittest.TestCase 를 사용할 경우 트랜잭션마다 데이터베이스를 비우는 작업을 하지 않아 성능은 좋아질 수 있습니다. 하지만 단위 테스트에서는 성공하나 테스트 스위트에서는 실패할 가능성이 존재합니다.

Running tests

작성된 테스트는 프로젝트의 manage.py 유틸리티의 test 명령으로 실행할 수 있습니다.

테스트 탐색은 unittest 모듈의 built-in test unittest 기반으로 합니다. 기본적으로 현재 작업 폴더 하위의 "test*.py" 형식의 파일 이름을 찾습니다.


./manage.py test 뒤에 파이썬 패키지 또는 TestCase subclass 또는 안의 메서드 이름를 작성하여 특정 단위의 테스트들 실행이 가능합니다.


아래처럼 특정 폴더 경로를 사용할 수도 있습니다.


-p (또는 —pattern) 옵션을 사용하여 파일 이름 패턴을 커스텀 할 수 있습니다.


테스트 실행 중에 Ctrl-C 를 입력하면 gracefully 종료됩니다. 종료되는 동안 실패 케이스와 에러 케이스 등등이 출력되고 평소같이 데이터베이스도 파괴됩니다. Ctrl-C 입력은 옵션에 —failfast 를 잊었을 때 사용하면 좋습니다.


Ctrl-C 입력을 통해 gracefull exit 이 진행중인 상태에서 한 번 더 Ctrl-C 를 입력하면 기대하는 것처럼 gracefully 종료되지 않습니다. 테스트 결과에 대한 리포트도 없고 데이터베이스도 파괴되지 않습니다.


Test with warnings enabledpython -Wa manage.py test 를 사용하여 deprecation warnings 또는 코드 개선점 등을 확인하는 것도 좋은 방법입니다.


The test database

테스트(모델 테스트)에는 production 이 아닌 데이터베이스가 필요합니다. 테스트를 위해 분리된 비어있는 데이터베이스가 생성됩니다.


모든 테스트가 실행되면 통과 실패 여부와 관계없이 테스트 데이터베이스는 제거됩니다.

test —keepdb 옵션을 사용하여 테스트 데이터베이스가 제거되는 것을 막을 수 있습니다. 이를 사용하면 실행 간에 테스트 데이터베이스를 보존할 수 있습니다. 데이터베이스가 없다면, 최초에는 생성될 것입니다. 최신 상태를 유지하기 위해 migration 도 적용됩니다.


이전에 설명한 것과 같이 테스트 실행을 강제로 중단하면, 테스트 데이터베이스가 제거되지 않습니다. 다음 실행 시 해당 데이터베이스를 다시 사용할 것 인지 제거할 것인지 묻게 됩니다. test —noinput 옵션을 사용하면 질문 없이 자동으로 데이터베이스를 제거합니다.


디폴트 테스트 데이터베이스 이름들은 DATABASES 의 각 NAME 값에 test_ 접두어를 추가하여 생성됩니다. SQLite 를 사용하고 있다면, 테스트는 기본적으로 in-memory 데이터베이스를 사용합니다. DATABASES 의 TEST 딕셔너리는 테스트 데이터베이스 설정에 관련된 몇가지 세팅들을 제공합니다. 예를 들어, DATABASES 의 TEST 딕셔너리에 NAME 을 지정하여 테스트 데이터베이스 이름을 변경할 수 있습니다.


테스트 데이터베이스에 세밀한 조정을 위해 CHARSET TEST 옵션을 사용할 수 있습니다. MySQL 의 경우 COLLATION 옵션을 사용할 수 있습니다. TEST 딕셔너리의 자세한 설명은 settings documentation 을 참고 바랍니다.


SQLites 의 in-memory 데이터베이스를 사용하면 shared cache 가 활성화 됩니다. 스레드 간에 데이터베이스를 공유하는 테스트를 작성할 수 있습니다.


Rollback emulation

마이그레이션에서 로드된 초기 데이터는 TestCase 테스트에서만 사용가능하고 TransactionTestCase 에서는 사용할 수 없으며, 트랜잭션을 지원하는 백엔드에서만 가능합니다.(트랜잭션을 지원하지 않는 대표적인 예 MyISAM) LiveServerTestCase 나 StaticLiveServerTestCase 같은 TransactionTestCase 에 의존하는 테스트도 마찬가지입니다.


Django 는 TestCase 또는 TransactionTestCase 의 본문에 serilized_rollback 옵션을 True 로 설정하여 테스트 케이스마다 데이터를 다시 로드 할 수 있습니다. 하지만 테스트 속도가 약 3배 느려질 수도 있습니다.


serialized 데이터가 두 번 로드 되는 것을 막기 위해, serialized_rollback=True 설정은 테스트 데이터베이스가 flush 될 때 post_migrate 시그널을 비활성화 합니다.


Other test conditions


설정 파일의 DEBUG 세팅과 관련 없이 Django 테스트는 DEBUG=False 로 실행됩니다. 이는 테스트 환경을production 결과와 일치시키기 위함입니다.


Understanding the test output


테스트가 실행될 때, 테스트 러너가 준비하는 과정을 메시지로 확인할 수 있습니다. verbosity 옵션을 사용하여 출력 메시지에 대한 미세한 조정이 가능합니다.


테스트 데이터베이스 생성이 완료되고 모든 테스트가 정상적으로 진행되었다면 아래과 같은 메시지가 출력됩니다.


테스트가 실패하게 되면 실패한 이유가 자세히 출력됩니다.


테스트 러너는 오류가 발생하면 리턴 코드가 1 성공하면 0 입니다. 쉘 스크립트 등에서 해당 테스트를 동작시키고 결과를 판단할 때 사용하면 좋습니다.


Speeding up the tests


Running tests in parallel

모든 테스트들이 독립성이 보장된다면 멀티 코어 하드웨어를 활용해 속도를 높일 수 있습니다. test —parallel 을 참고바랍니다.


Password hashing

default password hasher 는 느리게 설계되어있습니다. 테스트에서 많은 유저의 인증이 필요한 경우 커스텀 설정 파일을 만들고 PASSWORD_HASHERS 에서 빠른 해싱 알고리즘을 추가합니다.

fixture 에서 사용되는 알고리즘이 있다면 PASSWORD_HASHERS 에 추가 바랍니다.


Preserving the test database

test —keepdb 옵션은 테스트 실행 간에 테스트 데이터베이스를 유지합니다. 생성과 삭제 등을 스킵하여 테스트 실행 시간을 감소시킬 수 있습니다.

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari