Написание хороших тестов для приложений Django - PullRequest
28 голосов
/ 03 февраля 2010

Я никогда не писал тестов в своей жизни, но я бы хотел начать писать тесты для моих проектов Django.Я прочитал несколько статей о тестах и ​​решил попробовать написать несколько тестов для очень простого приложения Django или для запуска.

Приложение имеет два представления (представление списка и представление подробностей) и модельс четырьмя полями:

class News(models.Model):
    title = models.CharField(max_length=250)
    content = models.TextField()
    pub_date = models.DateTimeField(default=datetime.datetime.now)
    slug = models.SlugField(unique=True)

Я хотел бы показать вам мой файл tests.py и спросить:

Имеет ли это смысл?

Я даже проверяю правильные вещи?

Есть ли передовые практики, которым я не следую, и вы могли бы указать мне?

my tests.py (содержит 11 тестов):

# -*- coding: utf-8 -*-
from django.test import TestCase
from django.test.client import Client
from django.core.urlresolvers import reverse
import datetime
from someproject.myapp.models import News

class viewTest(TestCase):
    def setUp(self):
        self.test_title = u'Test title: bąrekść'
        self.test_content = u'This is a content 156'
        self.test_slug = u'test-title-bareksc'
        self.test_pub_date = datetime.datetime.today()

        self.test_item = News.objects.create(
            title=self.test_title,
            content=self.test_content,
            slug=self.test_slug,
            pub_date=self.test_pub_date,
        )

        client = Client()
        self.response_detail = client.get(self.test_item.get_absolute_url())
        self.response_index = client.get(reverse('the-list-view'))

    def test_detail_status_code(self):
        """
        HTTP status code for the detail view
        """
        self.failUnlessEqual(self.response_detail.status_code, 200)

    def test_list_status_code(self):
        """
        HTTP status code for the list view 
        """
        self.failUnlessEqual(self.response_index.status_code, 200)

    def test_list_numer_of_items(self):
        self.failUnlessEqual(len(self.response_index.context['object_list']), 1)      

    def test_detail_title(self):
        self.failUnlessEqual(self.response_detail.context['object'].title, self.test_title)    

    def test_list_title(self):
        self.failUnlessEqual(self.response_index.context['object_list'][0].title, self.test_title)

    def test_detail_content(self):
        self.failUnlessEqual(self.response_detail.context['object'].content, self.test_content)    

    def test_list_content(self):
        self.failUnlessEqual(self.response_index.context['object_list'][0].content, self.test_content) 

    def test_detail_slug(self):
        self.failUnlessEqual(self.response_detail.context['object'].slug, self.test_slug)    

    def test_list_slug(self):
        self.failUnlessEqual(self.response_index.context['object_list'][0].slug, self.test_slug)

    def test_detail_template(self):
        self.assertContains(self.response_detail, self.test_title)
        self.assertContains(self.response_detail, self.test_content)

    def test_list_template(self):       
        self.assertContains(self.response_index, self.test_title) 

Ответы [ 2 ]

18 голосов
/ 03 февраля 2010

Я не идеален в тестировании, но несколько мыслей:

По сути, вы должны проверить каждую функцию, метод, класс, что угодно, что вы написали сами.

Это означает, что вам не нужно тестировать функции, классы и т. Д., Которые предоставляет инфраструктура.

Тем не менее, быстрая проверка ваших тестовых функций:

  • test_detail_status_code и test_list_status_code:
    Хорошо, чтобы проверить, правильно ли вы настроили маршрутизацию. Еще важнее, когда вы предоставляете собственную реализацию get_absolute_url().

  • test_list_numer_of_items
    Хорошо, если определенное количество элементов должно быть возвращено представлением. Нет необходимости, если номер не важен (то есть произвольно).

  • test_detail_template и test_list_template:
    Хорошо, чтобы проверить, правильно ли установлены переменные шаблона.

  • Все остальные функции: необязательно.
    Здесь вы в основном тестируете, работает ли ORM должным образом, работают ли списки должным образом и можно ли получить доступ к свойствам объекта (или нет). Пока вы не изменились например save() метод модели и / или предоставляют вашу пользовательскую логику , я бы не проверял это. Вы должны доверять разработчикам фреймворка, что это работает правильно.

Вам нужно только проверить, что вы написали (пере).

Классы моделей могут быть особым случаем. Как я уже сказал, вам нужно их протестировать, если вы предоставляете пользовательскую логику. Но вы также должны проверить их на соответствие вашим требованиям . Например. может быть, что поле не может иметь значение null (или что оно должно быть определенного типа данных, например целое число). Поэтому вы должны проверить, что сохранение объекта завершается неудачей, если в этом поле есть значение null.
Это не проверяет ORM на правильность следования вашей спецификации, но проверяет, что спецификация все еще удовлетворяет вашим требованиям. Возможно, вы изменили модель и изменили некоторые настройки (случайно или из-за того, что забыли о требованиях).
Но вам не нужно проверять, например, такие методы, как save() или более, вы можете получить доступ к свойству.

Конечно, когда вы используете глючный сторонний код ... ну, все может быть иначе. Но поскольку Django использует сам тестовый фреймворк для проверки того, что все работает, я предполагаю, что он работает.

Подводя итог:
Проверьте свои требования, протестируйте свой собственный код.

Это только моя точка зрения. Может быть, у других есть лучшие предложения.

5 голосов
/ 03 февраля 2010

Разбейте свои тесты на два совершенно разных вида.

  • Модельные испытания. Поместите их в файл models.py вместе с моделью. Эти тесты будут использовать методы в ваших модельных классах. Вы можете сделать простой CRUD (Create, Retrieve, Update, Delete), чтобы просто доказать, что ваша модель работает. Не проверяйте каждый атрибут. Проверяйте значения по умолчанию и правила save(), если вам интересно.

    Для вашего примера создайте класс TestNews, который создает, получает, обновляет и удаляет элемент News. Обязательно проверьте результаты даты по умолчанию. Этот класс должен быть коротким и по существу. Вы можете, если ваше приложение требует этого, протестировать различные виды обработки фильтров. Ваш код модульного теста может (и должен) предоставить примеры «правильного» способа фильтрации News.

  • Тесты пользовательского интерфейса. Поместите их в отдельный файл tests.py. Эти тесты будут проверять функции представления и шаблоны.

    • Назовите TestCase с помощью "условия", которое вы создаете. "TestNotLoggedIn". "TestLoggedIn". "TestNoValidThis". "TestNotAllowedToDoThat". Ваш setUp выполнит вход в систему и любые другие шаги, необходимые для установления необходимого условия.

    • Назовите каждый метод испытания с указанием действия и результата. "test_get_noquery_should_list", "test_post_should_validate_with_errors", "test_get_query_should_detail".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...