Django
단위 테스트
수색…
테스트 - 완전한 예제
여기서는 새로운 Django 프로젝트 시작에 관한 문서를 읽었다 고 가정합니다. 프로젝트의 기본 앱의 이름이 td (테스트 구동의 약자)라고 가정 해 보겠습니다. 첫 번째 테스트를 만들려면 test_view.py 파일을 만들고 다음 내용을 복사하여 복사하십시오.
from django.test import Client, TestCase
class ViewTest(TestCase):
def test_hello(self):
c = Client()
resp = c.get('/hello/')
self.assertEqual(resp.status_code, 200)
이 테스트는 다음과 같이 실행할 수 있습니다.
./manage.py test
그리고 그것은 자연스럽게 실패 할 것입니다! 다음과 유사한 오류가 표시됩니다.
Traceback (most recent call last):
File "/home/me/workspace/td/tests_view.py", line 9, in test_hello
self.assertEqual(resp.status_code, 200)
AssertionError: 200 != 404
왜 그런 일이 일어날까요? 우리는 뷰를 정의하지 않았기 때문에! 그럼 해보 죠. views.py라는 파일을 만들고 다음 코드를 그 안에 넣으십시오.
from django.http import HttpResponse
def hello(request):
return HttpResponse('hello')
다음과 같이 / hello /를 편집하여 urls py를 편집하십시오.
from td import views
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^hello/', views.hello),
....
]
이제 테스트를 다시 실행하십시오 ./manage.py test
and viola !!
Creating test database for alias 'default'...
.
----------------------------------------------------------------------
Ran 1 test in 0.004s
OK
장고 모델을 효과적으로 테스트하기
가정 할 때
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('view_author', args=[str(self.id)])
class Book(models.Model):
author = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
private = models.BooleanField(default=false)
publish_date = models.DateField()
def get_absolute_url(self):
return reverse('view_book', args=[str(self.id)])
def __str__(self):
return self.name
테스트 예
from django.test import TestCase
from .models import Book, Author
class BaseModelTestCase(TestCase):
@classmethod
def setUpClass(cls):
super(BaseModelTestCase, cls).setUpClass()
cls.author = Author(name='hawking')
cls.author.save()
cls.first_book = Book(author=cls.author, name="short_history_of_time")
cls.first_book.save()
cls.second_book = Book(author=cls.author, name="long_history_of_time")
cls.second_book.save()
class AuthorModelTestCase(BaseModelTestCase):
def test_created_properly(self):
self.assertEqual(self.author.name, 'hawking')
self.assertEqual(True, self.first_book in self.author.book_set.all())
def test_absolute_url(self):
self.assertEqual(self.author.get_absolute_url(), reverse('view_author', args=[str(self.author.id)]))
class BookModelTestCase(BaseModelTestCase):
def test_created_properly(self:
...
self.assertEqual(1, len(Book.objects.filter(name__startswith='long'))
def test_absolute_url(self):
...
몇 점
-
created_properly
tests는 django 모델의 상태 속성을 확인하는 데 사용됩니다. 그들은 우리가 기본값, file_upload_paths 등을 변경 한 곳을 잡는 데 도움이됩니다. -
absolute_url
은 사소한 것 같지만 URL 경로를 변경할 때 버그를 예방할 수 있다는 것을 알았습니다. - 나는 모델 내에서 구현 된 모든 메소드에 대한 테스트 케이스를 비슷하게 작성한다 (
mock
객체 등을 사용하여) - 공통
BaseModelTestCase
를 정의함으로써 적절한 테스트를 위해 필요한 모델 간의 관계를 설정할 수 있습니다.
마지막으로 의심 스러울 때 테스트를 작성하십시오. 사소한 행동 변화는 세부 사항에주의를 기울임으로써 포착되며 오랫동안 잊혀진 코드 조각은 불필요한 문제를 일으키지 않습니다.
장고보기 액세스 제어 테스트
tl; dr : 두 개의 사용자 객체를 정의하는 기본 클래스를 만듭니다 (예 : user
및 another_user
). 다른 모델을 작성하고 세 개의 Client
인스턴스를 정의하십시오.
-
self.client
: 브라우저에 로그인 한user
self.client
. -
self.another_client
:another_user
의 클라이언트를another_user
self.another_client
. -
self.unlogged_client
:self.unlogged_client
않은 사람을self.unlogged_client
.
이제이 세 클라이언트 객체의 공개 URL과 비공개 URL에 모두 액세스하여 원하는 응답을 받아들입니다. 아래에서는 private
(소수의 권한있는 사용자 소유) 또는 public
(모든 사용자에게 public
) 중 하나 일 수있는 Book
개체에 대한 전략을 보여 드렸습니다.
from django.test import TestCase, RequestFactory, Client
from django.core.urlresolvers import reverse
class BaseViewTestCase(TestCase):
@classmethod
def setUpClass(cls):
super(BaseViewTestCase, cls).setUpClass()
cls.client = Client()
cls.another_client = Client()
cls.unlogged_client = Client()
cls.user = User.objects.create_user(
'dummy',password='dummy'
)
cls.user.save()
cls.another_user = User.objects.create_user(
'dummy2', password='dummy2'
)
cls.another_user.save()
cls.first_book = Book.objects.create(
name='first',
private = true
)
cls.first_book.readers.add(cls.user)
cls.first_book.save()
cls.public_book = Template.objects.create(
name='public',
private=False
)
cls.public_book.save()
def setUp(self):
self.client.login(username=self.user.username, password=self.user.username)
self.another_client.login(username=self.another_user.username, password=self.another_user.username)
"""
Only cls.user owns the first_book and thus only he should be able to see it.
Others get 403(Forbidden) error
"""
class PrivateBookAccessTestCase(BaseViewTestCase):
def setUp(self):
super(PrivateBookAccessTestCase, self).setUp()
self.url = reverse('view_book',kwargs={'book_id':str(self.first_book.id)})
def test_user_sees_own_book(self):
response = self.client.get(self.url)
self.assertEqual(200, response.status_code)
self.assertEqual(self.first_book.name,response.context['book'].name)
self.assertTemplateUsed('myapp/book/view_template.html')
def test_user_cant_see_others_books(self):
response = self.another_client.get(self.url)
self.assertEqual(403, response.status_code)
def test_unlogged_user_cant_see_private_books(self):
response = self.unlogged_client.get(self.url)
self.assertEqual(403, response.status_code)
"""
Since book is public all three clients should be able to see the book
"""
class PublicBookAccessTestCase(BaseViewTestCase):
def setUp(self):
super(PublicBookAccessTestCase, self).setUp()
self.url = reverse('view_book',kwargs={'book_id':str(self.public_book.id)})
def test_user_sees_book(self):
response = self.client.get(self.url)
self.assertEqual(200, response.status_code)
self.assertEqual(self.public_book.name,response.context['book'].name)
self.assertTemplateUsed('myapp/book/view_template.html')
def test_another_user_sees_public_books(self):
response = self.another_client.get(self.url)
self.assertEqual(200, response.status_code)
def test_unlogged_user_sees_public_books(self):
response = self.unlogged_client.get(self.url)
self.assertEqual(200, response.status_code)
데이터베이스 및 테스트
Django는 테스트시 특별한 데이터베이스 설정을 사용하여 테스트가 데이터베이스를 정상적으로 사용할 수 있지만 기본적으로 빈 데이터베이스에서 실행합니다. 한 테스트의 데이터베이스 변경 사항은 다른 테스트에서 볼 수 없습니다. 예를 들어 다음 테스트가 모두 통과합니다.
from django.test import TestCase
from myapp.models import Thing
class MyTest(TestCase):
def test_1(self):
self.assertEqual(Thing.objects.count(), 0)
Thing.objects.create()
self.assertEqual(Thing.objects.count(), 1)
def test_2(self):
self.assertEqual(Thing.objects.count(), 0)
Thing.objects.create(attr1="value")
self.assertEqual(Thing.objects.count(), 1)
비품
여러 테스트에서 데이터베이스 객체를 사용하려면 테스트 케이스의 setUp
메소드에서 생성하십시오. 또한 장고 프로젝트에서 조명기를 정의했다면 다음과 같이 포함시킬 수 있습니다 :
class MyTest(TestCase):
fixtures = ["fixture1.json", "fixture2.json"]
기본적으로 django는 각 app의 fixtures
디렉토리에있는 fixtures
찾고 있습니다. 추가 디렉토리는 FIXTURE_DIRS
설정을 사용하여 설정할 수 있습니다.
# myapp/settings.py
FIXTURE_DIRS = [
os.path.join(BASE_DIR, 'path', 'to', 'directory'),
]
다음과 같이 모델을 생성했다고 가정 해 보겠습니다.
# models.py
from django.db import models
class Person(models.Model):
"""A person defined by his/her first- and lastname."""
firstname = models.CharField(max_length=255)
lastname = models.CharField(max_length=255)
그러면 .json 픽스쳐는 다음과 같이 보일 수 있습니다.
# fixture1.json
[
{ "model": "myapp.person",
"pk": 1,
"fields": {
"firstname": "Peter",
"lastname": "Griffin"
}
},
{ "model": "myapp.person",
"pk": 2,
"fields": {
"firstname": "Louis",
"lastname": "Griffin"
}
},
]
테스트 데이터베이스 재사용
테스트 실행 속도를 높이기 위해 관리 명령에 테스트 데이터베이스를 다시 사용하도록 지시 할 수 있습니다 (테스트 실행 전과 테스트 데이터베이스가 생성되기 전에 삭제되는 것을 방지 할 수 있습니다). 이것은 다음과 같이 keepdb (또는 속기 -k
) 플래그를 사용하여 수행 할 수 있습니다.
# Reuse the test-database (since django version 1.8)
$ python manage.py test --keepdb
실행 된 테스트 수 제한
테스트 러너가 발견 할 모듈을 지정하여 manage.py test
가 실행하는 테스트를 제한 할 수 있습니다.
# Run only tests for the app names "app1"
$ python manage.py test app1
# If you split the tests file into a module with several tests files for an app
$ python manage.py test app1.tests.test_models
# it's possible to dig down to individual test methods.
$ python manage.py test app1.tests.test_models.MyTestCase.test_something
일련의 테스트를 실행하려면 파일 이름 패턴을 전달할 수 있습니다. 예를 들어, 모델과 관련된 테스트 만 실행할 수 있습니다.
$ python manage.py test -p test_models*
Creating test database for alias 'default'...
.................................................
----------------------------------------------------------------------
Ran 115 tests in 3.869s
OK
마지막으로 --failfast
사용하여 첫 번째 실패시 테스트 스위트를 중지 할 수 있습니다. 이 인수를 사용하면 스위트에서 발생할 수있는 잠재적 인 오류를 신속하게 얻을 수 있습니다.
$ python manage.py test app1
...F..
----------------------------------------------------------------------
Ran 6 tests in 0.977s
FAILED (failures=1)
$ python manage.py test app1 --failfast
...F
======================================================================
[Traceback of the failing test]
----------------------------------------------------------------------
Ran 4 tests in 0.372s
FAILED (failures=1)