Python unittest загадочно провалился из-за второго теста - PullRequest
0 голосов
/ 18 октября 2019

Я написал следующий модульный тест, который успешно выполняется при его запуске:

api \ test \ test_views.py:

class ProductListViewTest(APITestCase):

    def test_get_products(self):
        mock_products = MockSet()
        mock_products.add(MockModel(mock_name='e1', prod_id='1')  
        client = APIClient()
        with patch('api.models.Product.objects', mock_products):
            response = client.get(reverse('product-list'))

        serialized = ProductSerializer([{'prod_id': '1'}], many=True)

        self.assertEqual(response.data, serialized.data)

Остальная часть кода:

# api\views.py:

from api.models import Product

class ProductViewSet(viewsets.ModelViewSet):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer

# api\urls.py:
...
path('product/', views.ProductListView.as_view(), name='product'),
...

Однако, как только я добавляю второй тест в тот же TestCase, который использует APIClient, первый тест завершается неудачей (response.data содержит пустой массив) !!!

 def test_second_test(self):
        client = APIClient()
        response = client.get('/')
        self.assertEqual(True, True)

если я удаляю вызов client.get(), который даже не имеет смысла, первый тест снова проходит!

Редактировать: Одна вещь, которую я заметил, это то, что в ProductViewSet, Product является MockSet только когда я запускаю тест test_get_products индивидуально. Если я запускаю оба теста с «run all», Product имеет тип api.models.Product. Как будто исправление не происходило: /

1 Ответ

0 голосов
/ 18 октября 2019

Это распространенная проблема при тестировании DRF ModelViews. Переопределить get_queryset на ProductViewSet:

class ProductViewSet(viewsets.ModelViewSet):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer

    def get_queryset(self):
        return self.queryset.all()

Таким образом, ответ будет оцениваться на каждый запрос.

С django docs :

Когда QuerySet оценивается, он обычно кэширует свои результаты. Если данные в базе данных могли измениться после оценки QuerySet, вы можете получить обновленные результаты для того же запроса, вызвав all () для ранее оцененного QuerySet.

Ваш второй тест называется первымв тестовом прогоне и хранит пустой ответ в ProductViewSet.queryset. Поскольку queryset является переменной класса, она сохраняется между вызовами теста. Кроме того, django не знает, что состояние базы данных (макет) изменилось, поэтому используется кэшированный QuerySet.

...