Поиск…


Тестирование - полный пример

Предполагается, что вы прочитали документацию о запуске нового проекта Django. Предположим, что основное приложение в вашем проекте называется td (short для test driven). Чтобы создать свой первый тест, создайте файл с именем 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 /, отредактировав URL-адрес py следующим образом:

from td import views

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^hello/', views.hello),
    ....
]

Теперь повторите тест снова. / ./manage.py test снова и альта !!

Creating test database for alias 'default'...
.
----------------------------------------------------------------------
Ran 1 test in 0.004s

OK

Эффективное тестирование моделей Django

Предполагая класс

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 используются для проверки свойств состояния моделей django. Они помогают поймать sitautions, где мы изменили значения по умолчанию, file_upload_paths и т. Д.
  • absolute_url может показаться тривиальным, но я обнаружил, что это помогло мне предотвратить некоторые ошибки при изменении URL-адресов
  • Я также записываю тестовые примеры для всех методов, реализованных внутри модели (с использованием mock объектов и т. Д.),
  • Определяя общую BaseModelTestCase мы можем установить необходимые отношения между моделями для обеспечения правильного тестирования.

Наконец, когда вы сомневаетесь, напишите тест. Тривиальные изменения поведения улавливаются, обращая внимание на детали, и давно забытые фрагменты кода не приводят к ненужным проблемам.

Тестирование контроля доступа в представлениях Django

tl; dr : создать базовый класс, который определяет два пользовательских объекта (например, user и another_user ). Создайте другие модели и определите три экземпляра Client .

  • self.client : представление user зарегистрированного в браузере.
  • self.another_client : представление клиента another_user
  • self.unlogged_client : представление незарегистрированного лица

Теперь обращайтесь ко всем своим публичным и частным адресам из этих трех клиентских объектов и диктуйте ответ, который вы ожидаете. Ниже я продемонстрировал стратегию для объекта Book который может быть либо private (принадлежащим нескольким привилегированным пользователям), либо public (видимым для всех).

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 тестового примера. Кроме того, если вы определили приборы в своем проекте django, их можно включить так:

class MyTest(TestCase):
    fixtures = ["fixture1.json", "fixture2.json"]

По умолчанию django ищет светильники в каталоге 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 , используя --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)


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow