해당 포스트는 Django Framework 에 대한 기초적인 지식을 필요로한다.
아래의 링크를 통해 튜토리얼의 소스코드를 clone 할 수 있다.
https://github.com/deadlylaid/testing
단위테스트란 무엇인가?
단위테스트는 어플리케이션 내에 작성되어있는 코드가 올바르게 작동하고 있는지를 반복적으로 확인하기 위해 존재한다. 일반적으로 어플리케이션이 동작하는 데에는 무수히 많은 코드와 함수, 클래스등이 존재할 것이며 단위테스트는 이 복잡한 코드의 신뢰성을 보장하는 역할을 맡는다. 이러한 존재 의의로 인해 단위테스트는 '되도록' 지켜야할 몇 가지 특징들이 있다.
- 자동화 되어야한다.
- 테스트 되는 코드와 분리되어야 한다.
- 하나의 테스트는 하나의 기능 단위만 테스트해야 한다.
- 각 테스트는 서로 독립적이어야한다.
- 그 외
단위테스트를 진행하면서 유의해야할 점은, 단위테스트는 단순히 코드의 신뢰성만 보장할 뿐, 각각의 코드 단위가 실행되어 어플리케이션 기능이 올바르게 동작하는지는 신경쓰지 않는다는 점이다. 단위테스트는 단순히 짜여진 범위 내의 작은 단위만 검증할 뿐 각 단위가 모두 올바르게 연결되어 실행되는지는 검증하지 않는다.
Pytest
파이썬 표준 라이브러리인 unittest보다 좀 더 효율적으로 테스트를 작성하기 위해 만들어졌다. 이번 포스팅에서는 pytest를 이용하여 python 프레임워크인 django 단위 테스트를 진행해보려 한다.
선행적으로 설치되어야하는 목록은 아래와 같다.
- django
- pytest
- pytest-django (pytest의 django 확정 플러그인)
django-admin 명령어를 통해 프로젝트를 만든 후 Masterpice app을 생성하고 간단한 MTV 로직에 맞는 코드를 작성한다.
# model.py
class Masterpiece(models.Model):
name = models.Charfield(max_length=20)
author = models.Charfiled(max_length=20)
create_at = models.DataTimeField(auto_now_add=True)
price = models.models.DemicalField(decimal_places=2, max_digits=15)
# form.py
class MasterpieceModelForm(forms.ModelForm):
class Meta:
model = Masterpiece
fields = '__all__'
# view.py
class MasterpieceCreateView(CreateView):
model = Masterpiece
template_name = 'home.html'
form_class = MasterpieceModelForm
class MasterpieceListView(ListView):
model = Masterpiece
template_name = 'home.html'
일반적으로 pytest는 pytest.ini 를 이용하여 여러 설정을 추가할 수 있는데, django 테스트를 위해서 DJANGO_SETTINGS_MODULE 을 추가하여 django 프로젝트 테스트 setting을 설정한다.
; 파일의 위치는 manager.py 와 동일하다.
[pytest]
DJANGO_SETTINGS_MODULE = masterpiece.masterpiece.settings
python_files = *tests.py
처음 진행하게 될 단위 테스트는 아래와 같다.
- Masterpiece object create test
- CreateView Get, Post request test
- ListView Get request test
첫 테스트로 먼저 테이블 오브잭트가 올바르게 생성되는지를 확인하려고 한다.
def test_masterpiece_listview(client):
obj = Masterpiece.objects.create(
name='Creation of Adam',
author='Michelangelo',
price='10.99'
)
assert obj
오브젝트를 생성한 후, 해당 오브젝트가 정상적으로 생성되었는지 확인한다. pytest 명령어를 통해 테스트를 진행하면 예상치 못한 결과를 얻게 된다.
_ _ _ _ _ _ _ _ _ _ _ _ __ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <django.db.backends.sqlite3.base.DatabaseWrapper object at 0x104ae7710>,...
def _cursor(self, name=None):
> self.ensure_connection()
E Failed: Database access not allowed, use the "django_db" mark, or the "db" or "transactional_db" fixtures to enable it.
../boot/lib/python3.7/site-packages/django/db/backends/base/base.py:233: Failed
====================== 1 failed in 0.39 seconds =======================
기본적으로 pytest는 데이터베이스에 접근 권한이 없기 때문에, 오브젝트를 생성할 수도, 가져오지도 못한다. 때문에 이 문제를 해결하기 위해서는 몇 가지 방법이 있는데 가장 쉬운 방법은 pytest의 markers 를 이용해서 db접근이 가능하게 만들어주는 것이다.
markers 란
pytest의 markers는 테스트 함수에 metadata를 손쉽게 설정할 수 있도록 도와준다.
pytest에는 builtin makrers 가 몇 가지 존재하지만 필요하다면 스스로 marker를 만드는 것도 가능하다.
import pytest
@pytest.mark.django_db
def test_masterpiece_listview(client):
obj = Masterpiece.objects.create(
name='Creation of Adam',
author='Michelangelo',
price='10.99'
)
assert obj
그 다음 ListView 테스트를 진행해보려고 한다. 단순히 오브젝트를 가져와 리스팅하는 기능을 갖기 때문에 복잡할 것이 없다.
def test_listview_get_test(client):
resp = client.get(
reverse('list')
)
assert resp.status_code == 200
본래 status code 뿐 아니라 리스팅 여부도 테스트해야 하지만, 해당 내용에 대한 자세한 사항은 다음 포스팅때 하기로 한다.
다음으로 진행하게 될 테스트는 CreateView[GET, POST] 에 대한 테스트를 진행한다. 테스트하게 될 단위에는 modelform 검증도 함께 진행된다.
def test_modelform_test():
data = MasterpieceModelForm(
data={
'name': 'Creation of Adam',
'author': 'Michelangelo',
'price': '100.99',
}
)
assert data.is_valid()
def test_createview_get_test(client):
resp = client.get(reverse('create'))
assert resp.status_code == 200
assert isinstance(resp.context_data.get('form'), MasterpieceModelForm)
@pytest.mark.django_db
def test_createview_post_test(client):
resp = client.post(
reverse('create'),
data={'name': 'Creation of Adam', 'author': 'Michelangelo', 'price': '100.99'}
)
assert resp.status_code == 302
obj = Masterpiece.objects.first()
assert isinstance(obj, Masterpiece)
assert resp.url == reverse('list')
test_createview_post_test 에서 오브젝트의 생성 여부와, MasterpieceListView로 이동하는 것 까지 테스트했다. 해당 테스트 역시 오브젝트를 생성하기 위해 데이터베이스에 접근해야 하므로 markers 를 사용한다.
이상으로, pytest-django 간단한 튜토리얼 1부를 마친다.
다음 2부에 작성될 내용은 pytest에서 사용되는 fixture의 기능에 대해 알아볼 것이다.
'프로그래밍 > language' 카테고리의 다른 글
mysql character set error + django test (0) | 2020.05.17 |
---|---|
setup.py vs requirements.txt (0) | 2019.12.29 |
단위 테스트 pytest-django 튜토리얼 - [3] (0) | 2019.10.05 |
단위 테스트 pytest-django 튜토리얼 - [2] (0) | 2019.08.04 |
python 2.7은 곧 종료된다. (0) | 2019.07.06 |