Django Rest Framework 测试失败和通过,具体取决于函数的数量

Django Rest Framework tests fail and pass, depending on number of functions

我在 Django Rest Framework 中有一个测试 class,其中包含一个函数,如果它是 class 中唯一的函数,则该函数通过测试,如果它是两个或更多函数之一,则失败职能。

如果我运行下面的代码原样,即def test_audio_list(self)函数仍然被注释掉,测试通过两个断言语句。

如果我取消注释 def test_audio_list(self) 函数和 运行 测试,def test_audio_retrieve(self) 函数将失败并返回 404,而 def test_audio_list(self) 将通过。

这是我的完整测试用例(def test_audio_list(self): 被注释掉了)。

class AudioTests(APITestCase):
    # setup a test user and a factory
    # factory = APIRequestFactory()
    test_user = None

    def setUp(self):
        importer()
        self.test_user = User(username='jim', password='monkey123', email='jim@jim.com')
        self.test_user.save()

    # def test_audio_list(self):
    #     """
    #         Check that audo returns a 200 OK
    #     """
    #     factory = APIRequestFactory()
    #     view = AudioViewSet.as_view(actions={'get': 'list'})
    #
    #     # Make an authenticated request to the view...
    #     request = factory.get('/api/v1/audio/')
    #     force_authenticate(request, user=self.test_user)
    #     response = view(request, pk="1")
    #
    #     self.assertContains(response, 'audio/c1ha')
    #     self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_audio_retrieve(self):
        """
            Check that audo returns a 200 OK
        """
        factory = APIRequestFactory()
        view = AudioViewSet.as_view(actions={'get': 'retrieve'})

        # Make an authenticated request to the view...
        request = factory.get('/api/v1/audio/')
        force_authenticate(request, user=self.test_user)
        response = view(request, pk="1")

        self.assertContains(response, 'audio/c1ha')
        self.assertEqual(response.status_code, status.HTTP_200_OK)

运行 python manage.py test 上面不会产生错误。但是如果我取消注释 def test_audio_list(self) 函数,def test_audio_retrieve(self) 将失败并显示以下内容:

======================================================================
FAIL: test_audio_retrieve (api.tests.AudioTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/code/api/tests.py", line 96, in test_audio_retrieve
    self.assertContains(response, 'audio/c1ha')
  File "/usr/local/lib/python3.7/site-packages/django/test/testcases.py", line 446, in assertContains
    response, text, status_code, msg_prefix, html)
  File "/usr/local/lib/python3.7/site-packages/django/test/testcases.py", line 418, in _assert_contains
    " (expected %d)" % (response.status_code, status_code)
AssertionError: 404 != 200 : Couldn't retrieve content: Response code was 404 (expected 200)

。如果我更改 class 中函数的顺序,即将 def test_audio_retrieve(self) 放在 def test_audio_list(self) 之前,结果仍然相同。

我想我一定是在这里做错了什么,但我就是不能指手画脚。

非常感谢任何帮助。

干杯,

C

您不止一次使用了 'force_authenticate',也许您可​​以在设置中验证用户身份或使用 refresh_from_db

请检查:注意:force_authenticate直接将request.user设置为内存中的用户实例。如果您在更新保存的用户状态的多个测试中重复使用相同的用户实例,您可能需要在测试之间调用 refresh_from_db()。

https://www.django-rest-framework.org/api-guide/testing/

...

你能试试合并函数吗,像这样,

def test_audio(self):
    """
        Check that audio returns a 200 OK
    """
    factory = APIRequestFactory()
    view_retrieve = AudioViewSet.as_view(actions={'get': 'retrieve'})
    view_list = AudioViewSet.as_view(actions={'get': ‘list’})


    # Make an authenticated request to the view...
    request = factory.get('/api/v1/audio/')
    force_authenticate(request, user=self.test_user)

    # Retrieve
    response = view_retrieve(request, pk="1")
    self.assertContains(response, 'audio/c1ha')
    self.assertEqual(response.status_code, status.HTTP_200_OK)

    # List
    response = view_list(request, pk="1")
    self.assertContains(response, 'audio/c1ha')
    self.assertEqual(response.status_code, status.HTTP_200_OK)

Django 论坛上一位非常乐于助人的用户向我解释了这里的问题非常简单。

https://forum.djangoproject.com/t/apitestcase-with-apirequestfactory/420

我在我的对象的 ID 上使用了一个自动递增字段,当 Django 执行每个测试时,它首先通过调用 importer() 中的 def setUp(). After the each test function is run, Django then deletes the data and will again runsetUp() 来导入数据which in turn run进口商()```。

这会导致我的对象的 ID 随 class 中的每个测试函数而变化,即 运行。

我在我的测试用例中静态定义 ID,认为对象 ID 在整个测试用例中保持不变。

所以不用

# hardcoded PK
response = self.detail_view(request, pk="1")

我现在有

# dynamically assigned PK
pk = Audio.objects.first().id
response = self.detail_view(request, pk=pk)

长话短说,我需要动态获取要测试的对象的 ID,或者更好的是,创建一个不依赖于数据导入的测试用例。建议我使用 Factory Boy 之类的东西在测试用例中生成我自己的测试数据。