Как использовать pytest приспособления с django TestCase

#python #django #pytest #django-tests #pytest-django

#python #django #pytest #django-тесты #pytest-django

Вопрос:

Как я могу использовать pytest приспособление в TestCase методе? Несколько ответов на похожие вопросы, похоже, подразумевают, что мой пример должен работать:

 import pytest

from django.test import TestCase
from myapp.models import Category
  
pytestmark = pytest.mark.django_db

@pytest.fixture
def category():
    return Category.objects.create()
  
class MyappTests(TestCase):
    def test1(self, category):
        assert isinstance(category, Category)
  

Но это всегда приводит к ошибке:

 TypeError: test1() missing 1 required positional argument: 'category'
  

Я понимаю, что мог бы просто преобразовать этот тривиальный пример в функцию, и это сработало бы. Я бы предпочел использовать django TestCase , потому что он включает поддержку импорта традиционных файлов «django fixture», которые требуются для нескольких моих тестов. Преобразование моих тестов в функции потребует повторной реализации этой логики, поскольку не существует документированного способа импорта «django fixtures» с помощью pytest (или pytest-django).

версии пакетов:

 Django==3.1.2
pytest==6.1.1
pytest-django==4.1.0
  

Ответ №1:

Мне проще использовать подход «usefixtures». Он не показывает волшебный 2-й аргумент функции и явно помечает класс для наличия приспособлений.

 @pytest.mark.usefixtures("category")
class CategoryTest(TestCase):
    def test1(self):
        assert Category.objects.count() == 1
  

Комментарии:

1. Спасибо, но в моем случае это не сработало бы, потому что «pytest fixtures» не следует применять ко всем тестам в классе. Кроме того, мне нужно получить доступ либо к модели, возвращаемой из приспособления, либо к ее первичному ключу. При этом я нашел обходной путь, показанный в ответе, который я опубликовал.

2. Да, я подумал, что их не должно быть, но это функционально идентично тому, что вы пытались сделать выше. Я предпочитаю не смешивать pytest и TestCase, а также выбирать лучший инструмент для текущей работы.

Ответ №2:

Я решил переписать логику django fixture, используя «pytest fixture», который применяется в области session видимости. Все, что вам нужно, это одно приспособление в conftest.py файле в корне вашего тестового каталога:

 import pytest

from django.core.management import call_command

@pytest.fixture(scope='session')
def django_db_setup(django_db_setup, django_db_blocker):
    fixtures = [
        'myapp/channel',
        'myapp/country',
        ...
    ]

    with django_db_blocker.unblock():
        call_command('loaddata', *fixtures)
  

Это позволило мне полностью отказаться от тестов на основе классов и просто использовать тесты на основе функций.

Документы

Ответ №3:

Зачем вам нужен TestCase? Я обычно использую класс Python и создаю там тесты.

Пример

 import pytest
from django.urls import reverse
from rest_framework import status

from store.models import Book
from store.serializers import BooksSerializer


@pytest.fixture
def test_data():
    """Поднимает временные данные."""
    Book.objects.create(name='Book1', price=4000)


@pytest.fixture
def api_client():
    """Возвращает APIClient для создания запросов."""
    from rest_framework.test import APIClient
    return APIClient()


@pytest.mark.django_db
class TestBooks:
    @pytest.mark.usefixtures("test_data")
    def test_get_books_list(self, api_client):
        """GET запрос к списку книг."""
        url = reverse('book-list')
        excepted_data = BooksSerializer(Book.objects.all(), many=True).data
        response = api_client.get(url)
        assert response.status_code == status.HTTP_200_OK
        assert response.data == excepted_data
        assert response.data[0]['name'] == Book.objects.first().name