장고 앱을 생성할 때 기본으로 만들어지는 tests.py를 삭제하도록 하자
각각의 기능에 맞는 테스트 파일을("test_" 접두어를 붙여서) 따로 만들도록 하자
tests/
__init__.py
test_forms.py
test_models.py
test_views.py
테스트 메서드는 그 테스트 범위가 좁아야 한다.
하나의 단위테스트는 여러 개의 뷰나 모델 폼, 한 클래스의 여러 메서드를 담당해서는 안된다.
그러나 뷰 하나만으로도 모델, 폼, 메서드, 함수가 연관지어 호출되기 때문에 여려움이 있다.
환경을 최소한으로 구성하여 해당 문제를 피할 수 있다.
테스트 실행을 위한 최소한의 레코드를 setUp() 메서드를 사용하여 생성
# flavors/tests/test_api.py
import json
from django.test import TestCase
from django.urls import reverse
from flavors.models import Flavor
class FlavorAPITests(TestCase):
def setUp(self):
Flavor.objects.get_or_create(title='A Title', slug='a-slug')
def test_list(self):
url = reverse('flavors:flavor_object_api')
response = self.client.get(url)
self.assertEquals(response.stasus_code, 200)
data = json.loads(response.content)
self.assertEquals(len(data), 1)
# flavors/tests/test_api.py
import json
from django.test import TestCase
from django.urls import reverse
from flavors.models import Flavor
class DjangoRestFrameworkTests(TestCase):
def setUp(self):
Flavor.objects.get_or_create(title='title1', slug='slug1')
Flavor.objects.get_or_create(title='title2', slug='slug2')
self.create_read_url = reverse('flavors:flavor_rest_api')
self.read_update_delete_url = reverse('flavors:flavor_rest_api', kwargs={'slug': 'slug1'})
def test_list(self):
response = self.client.get(self.create_read_url)
# 생성된 두 타이틀 확인
self.assertContains(response, 'title1')
self.assertContains(response, 'title2')
def test_detail(self):
response = self.client.get(self.read_update_delete_url)
data = json.loads(response.content)
content = {'id': 1, 'title': 'title1', 'slug': 'slug1', 'scoops_remaining': 0}
self.assertEquals(data, content)
def test_create(self):
post = {'title': 'title3', 'slug': 'slug3'}
response = self.client.post(self.create_read_url, post)
data = json.loads(response.content)
self.assertEquals(response.status_code, 201)
content = {'id': 3, 'title': 'title3', 'slug': 'slug3', 'scoops_remaining': 0}
self.assertEquals(data, content)
self.assertEquals(Flavor.objects.count(), 3)
def test_delete(self):
response = self.client.delete(self.read_update_delete_url)
self.assertEquals(response.status_code, 204)
self.assertEquals(Flavor.objects.count(), 1)
django.test.client.RequestFactory는 모든 뷰에 대해 첫 번째 인자로 이용할 수 있는 인스턴스를 제공
(to generate a request instance that can be used as the first argument to any view.) ????
RequestFactory and Client have some very different use-cases. To put it in a single sentence: RequestFactory returns a request, while Client returns a response.
기본 장고 테스트 클라이언트보다 독립된 환경을 제공
단, 세션과 인증을 포함한 미들웨어를 지원하지 않기 때문에 추가적인 작업이 요구된다.
세션을 필요로 하는 뷰를 테스트 하고자 하면 아래와 같이 작성 할 수 있다.
from django.contrib.auth.models import AnonymousUser
from django.contrib.sessions.middleware import SessionMiddleware
from django.test import TestCase, RequestFactory
form .views import cheese_flavors
def add_middleware_to_request(request, middleware_class):
middleware = middleware_class()
middleware.process_request(request)
return request
def add_middleware_to_response(request, middleware_class):
middleware = middleware_class()
middleware.process_response(request)
return request
class SavoryIceCreamTest(TestCase):
def setUp(self):
self.factory = RequestFactory()
def test_cheese_flavors(self):
request = self.factory.get('/cheesy/broccoli/')
request.user = AnonymousUser()
request = add_middleware_to_request(request, SessionMiddleware)
request.session.save()
response = cheese_flavors(request)
self.assertContains(response, 'bleah!')
최대한 테스트 커버리지를 증가시키는 게임
단계
테스트 작성하기
테스트 실행 및 커버리지 리포트 작성
$ coverage run manage.py test -settings-twoscoops.settings.test
리포트 생성
$ coverage html --omit="admin.py"
규칙