Django: 무엇을 테스트하고, 왜, 어떻게 하는지.(코드)
카탈로그
뉴스 보도
우선, 우리는 무엇을 테스트해야 하는지 알아야 한다.앞서 말씀드린 바와 같이 Django의 바닐라 모델이나 Django ORM과python의 내장 함수를 테스트할 필요가 없습니다.
이것이 바로 범위의 편리함이다. 초보자에게는 우리가 테스트해야 할 기능을 찾을 수 있는 편리한 방식이다.
테스트 모델
프로젝트에 새로 작성된
index.html
폴더에서 htmlscov
를 엽니다.book-library > htmlscov > index.html
우리는 이러한 상황을 보게 될 것이다.우리한테 가자
catalog/models.py
.빨간색 줄은 우리가 테스트해야 할 코드 줄을 표시하고, 백분율은 테스트가 얼마나 많은 코드를 덮어썼는지 표시한다.
Dell
Book
모델을 고려하면 다음과 같습니다.class Book(models.Model):
"""Model representing a book
"""
title = models.CharField(max_length=200)
author = models.ForeignKey('Author', on_delete=models.SET_NULL, null=True)
summary = models.TextField(
max_length=1000, help_text='Enter a brief description of the book')
isbn = models.CharField('ISBN', max_length=13, unique=True,
help_text='13 Character <a href="https://www.isbn-international.org/content/what-isbn">ISBN number</a>')
genre = models.ManyToManyField(Genre, help_text='Select a genre for this book', related_name='books')
def __str__(self):
return self.title
def get_absolute_url(self):
"""Returns the url to access a detail record for this book.
"""
return reverse('book-detail', args=[str(self.id)])
테스트 모델 실현
class TestModels(TestCase):
@classmethod
def setUpTestData(self):
thriller = Genre.objects.create(name='thriller')
scifi = Genre.objects.create(name='scifi')
book = Book.objects.create(
title='test title',
summary='test summary',
isbn='test isbn',
)
book.genre.set([thriller.pk, scifi.pk])
def test_book_has_genre(self):
"""checks for genres in book
"""
book = Book.objects.first()
self.assertEqual(book.genre.count(), 2)
def test_book_str(self):
"""Checks str for book
"""
book = Book.objects.first()
self.assertEqual(str(book), "test title")
def test_book_absolute_url_with_200(self):
book = Book.objects.first()
self.assertEqual(book.get_absolute_url(), '/catalog/book/1')
response = self.client.get(book.get_absolute_url())
self.assertEqual(response.status_code, 200)
검측str
먼저 우리는 데이터를 설정한 다음에 테스트
str
를 표시한다. def test_book_str(self):
"""Checks str for book
"""
book = Book.objects.first()
self.assertEqual(str(book), "test title")
주의해야 할 점은 테스트 방법의 명칭은 시종test_
으로 시작해야 하며 테스트의 내용을 이해하기 위해 정확해야 한다는 것이다.단, 이름이 정확하지 않거나 의미가 없다고 생각되면, 무엇을 해야 하는지 설명하기 위해docstring을 사용하십시오.테스트 다대다
def test_book_has_genre(self):
"""checks for genres in book
"""
book = Book.objects.first()
self.assertEqual(book.genre.count(), 2)
우리가 이 책을 창작할 때, 우리는 이 책을 위해 두 가지 장르를 지정하였다.우리는 단지 책 속의 장르 수를 검사할 뿐이다. 이것은 장르 분배의 성공을 알려준다.절대 Url 테스트
def test_book_absolute_url_with_200(self):
book = Book.objects.first()
self.assertEqual(book.get_absolute_url(), '/catalog/book/1')
response = self.client.get(book.get_absolute_url())
self.assertEqual(response.status_code, 200)
우리 Book
모델에서 우리는 책 한 권의 정보를 얻는 get_absolute_url
라는 방법이 있다.우리는 상태 코드가 200인지 확인하고 get_absolute_url
방법이 실제적으로 정확한 URL인지 확인합니다.테스트 뷰
우리의 관점을 검증하기 위해서 우리는 이용할 것이다.
주의: 이것은 엄격한 의미의 단원 테스트가 아니다.실제로 Django 보기 코드를 위한 독립된 단위 테스트를 작성하는 것은 상당히 어렵다.
우리는 보기의 여러 내용을 검사할 수 있지만, 이것들은 흔히 볼 수 있는 내용들이다.
GET
와 POST
가 모두 제 방식대로 작동하는지 여부.index
시도를 참고하여 테스트를 진행할 것이다.from .models import Book, Author, BookInstance, Genre
from django.contrib.auth.decorators import login_required
@login_required(login_url='/login/')
def index(request):
"""View function for home page of site."""
# Generate counts of some of the main objects
num_books = Book.objects.all().count()
num_instances = BookInstance.objects.all().count()
# Available books (status = 'a')
num_instances_available = BookInstance.objects.filter(status__exact='a').count()
num_authors = Author.objects.count()
# Number of visits to this view, as counted in the session variable.
num_visits = request.session.get('num_visits', 0)
request.session['num_visits'] = num_visits + 1
context = {
'num_books': num_books,
'num_instances': num_instances,
'num_instances_available': num_instances_available,
'num_authors': num_authors,
'num_visits': num_visits,
}
# Render the HTML template index.html with the data in the context variable
return render(request, 'index.html', context=context)
테스트 보기 구현
from django.test import TestCase
from catalog.models import Author
from django.urls import reverse
from django.contrib.auth.models import User
from model_bakery import baker
class IndexViewTest(TestCase):
@classmethod
def setUpTestData(cls):
User.objects.create_user(username='test_user', password='test_password')
books = baker.make('catalog.Book', _quantity=10)
def test_view_deny_anonymous(self):
"""Test the view for unauthenticated user if unauthenticated will redirect to login page
"""
response = self.client.get('/catalog/')
self.assertRedirects(response, '/login/?next=/catalog/')
response = self.client.post('/catalog/')
self.assertRedirects(response, '/login/?next=/catalog/')
def test_view_url_accesible_by_name(self):
"""Test view is accesible by the reverse method
"""
self.client.login(username='test_user', password='test_password')
response = self.client.get(reverse('index'))
self.assertEqual(response.status_code, 200)
response = self.client.post(reverse('index'))
self.assertEqual(response.status_code, 200)
def test_view_uses_correct_template_(self):
"""Test view is using correct template
"""
self.client.login(username='test_user', password='test_password')
response = self.client.get(reverse('index'))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'index.html')
def test_view_has_context_num_books(self):
self.client.login(username='test_user', password='test_password')
response = self.client.get(reverse('index'))
self.assertEqual(response.status_code, 200)
self.assertTrue('num_books' in response.context)
self.assertEqual(response.context['num_books'], 10)
무단 사용자 거부
def test_view_deny_anonymous(self):
"""Test the view for unauthenticated user if unauthenticated will redirect to login page
"""
response = self.client.get('/catalog/')
self.assertRedirects(response, '/login/?next=/catalog/')
response = self.client.post('/catalog/')
self.assertRedirects(response, '/login/?next=/catalog/')
인증되지 않은 사용자가 거부되었는지 확인하고 로그인 페이지로 다시 지정합니다.URL은 이름으로 액세스됨
def test_view_url_accessible_by_name(self):
"""Test view is accessible by the reverse method
"""
self.client.login(username='test_user', password='test_password')
response = self.client.get(reverse('index'))
self.assertEqual(response.status_code, 200)
response = self.client.post(reverse('index'))
self.assertEqual(response.status_code, 200)
우리는 reverse
방법이 유효한지 확인하고 200
와 GET
방법의 상태 코드POST
를 얻었다.올바른 템플릿 사용 방법
def test_view_uses_correct_template_(self):
"""Test view is using correct template
"""
self.client.login(username='test_user', password='test_password')
response = self.client.get(reverse('index'))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'index.html')
이것은 assertTemplateUsed
방법이 정확한 템플릿을 사용했는지 검사할 것입니다.시험서 수량
def test_view_has_context_num_books(self):
self.client.login(username='test_user', password='test_password')
response = self.client.get(reverse('index'))
self.assertEqual(response.status_code, 200)
self.assertTrue('num_books' in response.context)
self.assertEqual(response.context['num_books'], 10)
이런 방법에서 우리는 도서의 수량 분배가 정확한지 시험한다.우리는 이곳에서 model-bakery를 사용하여 10개Book
의 실례를 만들었다.테스트 테이블
표는 단원 테스트를 쉽게 진행할 수 있다.우리는 표에서 검증 테스트를 진행할 수 있다.그것들은 값 사전을 받아들여 검증하고 오류나 삭제된 데이터를 되돌려줍니다.
우리의 프로젝트에서 우리는 표가 없기 때문에 본 강좌를 위해 표를 하나 만들자.
from django import forms
from .models import Book
class AddBookForm(forms.ModelForm):
class Meta:
model = Book
fields = ["title"]
def clean_title(self):
title = self.cleaned_data['title']
if not title:
return title
if not title[0].isupper():
self.add_error("title", "Should start with an uppercase")
if title.endswith("."):
self.add_error("title", "Should not end with a full stop")
return title
우리는 모델에 몇 가지 검증을 추가해서 그것을 테스트할 것이다.우리 테스트는 이랬을 거야.
from django.test import TestCase
from catalog.forms import AddBookForm
class AddBookFormTests(TestCase):
def test_title_starting_lowercase(self):
form = AddBookForm(data={"title": "a lowercase title"})
self.assertEqual(
form.errors["title"], ["Should start with an uppercase"]
)
def test_title_ending_full_stop(self):
form = AddBookForm(data={"title": "A stopped title."})
self.assertEqual(
form.errors["title"], ["Should not end with a full stop"]
)
def test_title_with_ampersand(self):
form = AddBookForm(data={"title": ""})
self.assertEqual(
form.errors["title"], ["This field is required."]
)
우리가 표에서 보듯이, 우리는 주로 테스트 검증을 한다.셀 테스트와 함께 통합 테스트를 추가하려는 경우 클라이언트를 사용하여 다음을 수행하여 유효성을 검사할 수 있습니다. def test_title_starting_lowercase(self):
response = self.client.post(
"/books/add/", data={"title": "a lowercase title"}
)
self.assertEqual(response.status_code, HTTPStatus.OK)
self.assertContains(
response, "Should start with an uppercase letter", html=True
)
다음에 토론할 화제
나는 이 시리즈에서 가능한 한 많이 소개하려고 했지만, 테스트에 있어서는 해야 할 일이 매우 많다.나는 곧 발표될 블로그에서 이 화제들을 소개하려고 시도할 것이다.짧은 목록은 다음과 같습니다.
unittest
와 유사한 테스트 프레임워크입니다.우리도 이걸로 대체할 수 있다unittest
결론
한마디로 테스트를 작성할 구체적인 방법은 없다.이것은 당신이 종사하고 있는 프로젝트나 당신이 있는 회사에 달려 있다.모든 사람은 자신의 방식으로 코드를 테스트할 수 있다.
내가 너에게 줄 수 있는 마지막 조언은 테스트를 쓰는 것을 두려워하지 말라는 것이다.그래, 처음에는 무서울 수도 있지만, 테스트를 작성하기 시작하면 코드를 더 잘 이해할 수 있다. 이것은 자신을 의심하게 하고, 모든 프로그램이 잘못될 수 있는 상황을 생각하게 하며, 더 좋은 프로그래머가 되도록 자극할 것이다.
오늘 여기서 궁금한 사항이 있으시면 댓글로 남겨주시거나 다른 질문이 있으시면 주저 없이 아래 플랫폼을 통해 연락 주세요GitHub.
Reference
이 문제에 관하여(Django: 무엇을 테스트하고, 왜, 어떻게 하는지.(코드)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/rabbilyasar/django-testing-the-what-why-and-how-3b8l텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)