Python单元测试神秘地由于第二次测试而失败

时间:2019-10-18 06:44:52

标签: python django python-unittest python-unittest.mock

我编写了以下单元测试,当我运行它时,它会成功:

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'),
...

但是,一旦我将第二个测试添加到使用API​​Client的同一TestCase中,第一个测试就会失败(response.data包含一个空数组)!

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

如果我删除了client.get()调用(甚至没有意义),则第一个测试再次通过!

编辑:我观察到的一件事是,在ProductViewSet中,Product仅当我分别运行test test_get_products时才是MockSet。如果使用“全部运行”运行两个测试,则Product的类型为api.models.Product。好像没有进行修补:/

1 个答案:

答案 0 :(得分:0)

这是测试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以来,数据库中的数据可能已更改。   评估后,您可以通过调用以下查询获取同一查询的更新结果   先前评估过的QuerySet上的all()。

您的第二个测试在测试运行中被首先调用,并将空响应存储在ProductViewSet.queryset中。因为queryset是一个类变量,所以它在测试调用之间仍然存在。另外,django不知道数据库(模拟的)状态已更改,因此使用了缓存的QuerySet

相关问题