pytest-django
는 django
프로젝트에서 pytest
를 사용하기 위한 플러그인pytest
와 pytest-django
는 Standard Django Test suite
와 Nose Test suite
호환됨django
의 manage.py test
를 사용하지 않고 pytest
명령어를 사용manage.py
를 사용하지 않는 이유는 unittest
를 임포트해서 TestCase
클래스의 서브 클래스로 선언할 필요가 없고, 단순하게 테스트 함수만 작성하는 것만으로 테스트를 작성할 수 있기 때문Fixture
를 관리할 수 있는 편리함과 pytest
의 다양한 플러그인도 사용할 수 있다는 장점이 있음django
에는 기본 테스트 모듈이 내재 되어 있음Pytest
를 별도로 실행을 해야하는 걸까?django
내장 테스트는 Boiler-Plate
가 존재set
이 단일 클래스(django.test.TestCase
)를 상속받아 운영pytest
는 멀티 실행을 지원Tip!
Boiler-Plate
(보일러플레이트)란?
- 최소한의 변경으로 여러 곳에서 재사용되며 반복적으로 비슷한 형태를 띄는 코드를 말함
- 어원: 보일러플레이트 코드의 어원은 신문사업에서 나왔음
- 1890년대에 광고나 컬럼과 같이 계속 사용되는 텍스트 인쇄판은 부드러운 납 대신 강철로 찍기 시작했는데 이를
Boiler-Plate
라고 불렀음
django
class
상속으로 이루어짐assert
를 각 class
의 method
로 평가해야 함pytest
function
단위로 테스트를 작성 할 수 있음assert
로 테스트를 평가할 수 있음django
외 다른 파이썬 프로젝트에도 도입이 가능config
를 파일로 지정해 놓을 수 있으며 fixture
를 정해놓고 여러 곳에서 원하는 순서에 맞추어 실행시켜 볼 수 있음$ pip install pytest-django
# pytest.ini - Project root folder
# 아래 설정을 잡아 주지 않을 경우, pytest 실행 시 에러 발생
[pytest]
DJANGO_SETTINGS_MODULE = project.settings
django
프로젝트의 설정을 사용하기 때문에 pytest.ini
파일에 위와 같이 명시하거나 --ds=project.settings
또는 DJANGO_SETTINGS_MODULE
환경변수를 설정해야 함python path
관리pytest-django
는 기본적으로 프로젝트의 manage.py
파일을 찾아보고 그 디렉토리를 python path
에 자동으로 추가함$ pytest test.py directory
pytest-django
는 manage.py
또는 django-admin.py
를 이용해 테스트를 실행하지 않고, 단독으로 pytest
명령어를 실행하는 방식을 사용pytest.ini
에서 지정 가능[pytest]
addopts = --reuse-db
—db-reuse
—create-db
models
변경 사항을 반영 할 수 있음default
로 —db-reuse
를 기본으로 설정해두고 DB 스키마 변경시에만 사용하는 것을 추천—migration
models
스키마 변경이 있을 경우 migration
을 진행django
DB 가 아닌 테스트용 DB에 적용—no-migration
pytest-django
는 테스트할 때 DB를 접근하는 것에 대해 보수적으로 다룸pytset-django
는 pytest mark
를 사용pytest.marks.db_django
marks
를 활용import pytest
@pytest.mark.django_db
def test_my_user():
me = User.objects.get(username='me')
assert me.is_superuser
mark
를 설정할 경우 모든 테스트에 적용할 수 있음import pytest
pytestmark = pytest.mark.django_db
@pytest.mark.django_db
class TestUsers:
pytestmark = pytest.mark.django_db
def test_my_user(self):
me = User.objects.get(username='me')
assert me.is_superuser
django
자체에 TransactionTestCase
클래스는 트랜젝션을 통해 격리된 상태에서 테스트를 수행하게 하고, 테스트를 마치면 DB 초기화를 해줌django_db mark
에 Transaction=True
파라미터를 전달@pytest.mark.django_db(transaction=True)
def test_spam():
pass
--reuse-db
은 데이터베이스를 재사용하기 위한 실행 옵션이고, --create-db
는 데이터베이스를 강제로 다시 생성하는 실행 옵션--reuse-db
를 사용하면 새로운 테스트 전용 DB가 생성되는데 모든 테스트가 종료 되더라도 테스트 DB는 지워지지 않음--reuse-db
를 사용하면 이전 테스트 DB를 다시 사용하게 됨--reuse-db
옵션을 기본 pytest.ini
옵션으로 지정하고, 스키마가 변경되었거나 했을 때 --create-db
옵션을 사용하는 것을 추천[pytest]
addopts = --reuse-db
--nomigrations
를 사용할 경우 django migrations
와 모든 모델 클래스 검사를 위한 DB 생성을 수행하지 않음pytest.marker
를 이용해 테스트 함수나 클래스에 메타 데이터를 쉽게 설정할 수 있음pytest.mark.django_db
pytest.mark.urls
django
의 URLCONF
을 직접 지정할 수 있음myapp.test_urls
rf
: django.utils.RequestFactory
인스턴스middleware
를 거치지 않고 바로 view
로 연결되는 request
를 만듬request.user
가 없어서 별도로 부착을 해줘야 함from myapp.views import my_view
def test_details(rf, admin):
request = rf.get('/customer/details')
# Remember that when using RequestFactory, the request does not pass
# through middleware. If your view expects fields such as request.user
# to be set, you need to set them explicitly.
# The following line sets request.user to an admin user.
request.user = admin
response = my_view(request)
assert response.status_code == 200
client
: django.test.Client
인스턴스def test_with_client(client):
response = client.get('/')
assert response.content == 'Foobar'
Tip! 추가 내용
Tip! 추가 내용
$ pytest
test_*.py
또는 *_test.py
파일을 모두 실행root
경로에서 특정 디렉토리 내부의 테스트 파일을 수행해야한다면, 아래와 같이 root
경로 기준 파일 위치를 입력하여 테스트 파일을 실행$ python -m pytest {디렉터리명}/{테스트파일명}.py
-k
옵션을 사용test_
로 시작해야만 테스트 함수로 인식$ pytest {테스트파일명}.py -k {테스트함수명}
Failed
건만 F
로 출력하고 Passed
건은 .
으로 표시-v
옵션 추가 시에는 각 테스트 함수 실행 결과를 출력-v
옵션으로는 내용이 일부 생략될 수 있음-vv
옵션을 추가하면 -v
옵션보다 verbosity level
을 높여 더 자세한 테스트 실행 결과를 출력Failed
건에 대한 stdout
, stderr
메세지는 캡쳐됨-s
옵션을 사용--capture=no
의 shortcut
이라고 볼 수 있음Passed
건에 대해서도 stdout
, stderr
메세지를 캡쳐하고 싶다면 --capture=tee-sys
옵션을 사용하면 됨short test summary info
에 출력되는 테스트 결과에 대한 옵션N
f
E
s
x
X
p
P
a
A
-r
옵션 뒤에 붙이는 문자에 따라 short test summary info
가 출력됨-rfE
로 Failed
와 Error
건이 출력됩니다.-rA
-ra
Passed
건 제외하고 모든 테스트 결과 출력-fEs
Failed
, Error
, Skipped
건 출력-rN
Failed
가 하나라도 발생할 때 테스트 수행을 멈추고 싶은 경우 -x
옵션을 사용Failed
N건 일 때 테스트 수행을 멈추고 싶은 경우 --maxfail=N
옵션을 사용--collect-only
옵션을 사용JUnit XML
형식의 테스트 결과 리포트를 출력하기 위해 --junit-xml={디렉터리명}/{xml리포트파일명}.xml
옵션을 사용pytest
실행 후 Jenkins
에서 빌드 후 조치로 Publish JUnit test result report
에서 해당 xml
파일 맵핑 설정을 해두면, Jenkins
빌드 결과 Test Result
메뉴에서 테스트 결과를 확인 가능--color=yes
옵션을 사용하면 테스트 결과 출력 시, 색상을 입힐 수 있음Jenkins Console Output
에서 테스트 결과 확인 시, Passed
/Failed
을 강조된 색상으로 확인할 수 있어 유용$ pytest -h
pytest -h
명령어로 그 외 옵션 확인 가능pytest.ini
파일에서 아래와 같이 테스트 파일로 인식할 파일 형태나 기본 실행할 명령어 옵션을 설정할 수 있음[pytest]
python_files = test_*.py *_tests.py check_*.py
addopts = -vv --maxfail=10