Django更简单的单元测试需要比稍微复杂的单元测试长10倍

时间:2018-05-14 21:29:04

标签: django unit-testing mocking

我正在Django==1.11python==2.7.12进行一些简单的单元测试。所有类似测试的测试执行时间都在0.0040 seconds左右,例如自定义suspend操作,该操作包含在帖子底部的test中。所有使用的类,表单,称为函数都在所有测试中被模拟。但是,unsuspend操作的测试耗时是执行时间的10倍,平均值为0.0400 seconds我不明白为什么,因为它甚至比suspend操作稍微简单一些

# The custom unsuspend DRF action being tested
@action(methods=['get'], detail=True, permission_classes=[OrganizationBasePermissions])
def unsuspend(self, request, uuid):
    organization = self.get_object()

    start = datetime.datetime.now()
    mc_organization.services.organization.unsuspend(organization=organization)
    end = datetime.datetime.now()

    print('service call duration:', end - start)
    # ('service call duration:', datetime.timedelta(0, 0, 143))

    serializer = self.get_serializer(instance=organization)
    return Response(data=serializer.data, status=status.HTTP_200_OK)

# The unittest of the unsuspend action above
@mock.patch('mc_organization.api.viewsets.organization.Response')
@mock.patch('mc_organization.api.viewsets.organization.ModelViewSet.get_serializer')
@mock.patch('mc_organization.api.viewsets.organization.'
            'mc_organization.services.organization.unsuspend')
@mock.patch('mc_organization.api.viewsets.organization.ModelViewSet.get_object')
def test_viewset_unsuspend_action(self, get_object_mock, unsuspend_service_mock, get_serializer_mock,
                                  response_mock):
    get_object_mock.return_value = self.organization
    get_serializer_mock.return_value = self.serialized_organization

    self.viewset.unsuspend(request=self.request, uuid=self.organization.uuid)

    self.assertEqual(get_object_mock.call_count, 1)
    unsuspend_service_mock.assert_called_once_with(organization=self.organization)
    get_serializer_mock.assert_called_once_with(instance=self.organization)
    response_mock.assert_called_once_with(data=self.serialized_organization.data, status=status.HTTP_200_OK)

当打印被调用的方法以查看它们是否被正确模拟时,结果显示 预期的模拟值:

print('mocked get object?:', self.get_object())
print('mocked service?:', mc_organization.services.organization.unsuspend)
print('mocked get_serializer?:', self.get_serializer())
print('mocked Response?:', Response())

# ('mocked get object?:', <MagicMock name='mock.user.organization' id='139678650884304'>)
# ('mocked service?:', <MagicMock name='unsuspend' id='139678651183504'>)
# ('mocked get_serializer?:', <MagicMock name='get_serializer()' id='139678650905808'>)
# ('mocked Response?:', <MagicMock name='Response()' id='139678651836496'>)

我正在使用django-slowtests来跟踪我最慢的测试,结果如下:

5 slowest tests:
0.0427s test_viewset_unsuspend_action (mc_organization.tests.api.viewsets.organization.test_u_viewset.OrganizationViewSetUnitTestCase)
0.0051s test_viewset_suspend_action_with_valid_request_data (mc_organization.tests.api.viewsets.organization.test_u_viewset.OrganizationViewSetUnitTestCase)
...

下面的暂停动作测试稍微(非常轻微)更复杂,执行时间减少了近10倍:

# The custom DRF action suspend, which is more complex but takes less time to execute
@action(methods=['post'], detail=True, permission_classes=[OrganizationBasePermissions])
def suspend(self, request, uuid):
    organization = self.get_object()

    form = OrganizationSuspendForm(data=request.data, organization=organization)

    if not form.is_valid():
        return Response(data=form.errors, status=status.HTTP_400_BAD_REQUEST)

    mc_organization.services.organization.suspend(
        organization=organization,
        reason=form.cleaned_data.get('suspended_reason')
    )
    serializer = self.get_serializer(instance=organization)

    return Response(data=serializer.data, status=status.HTTP_200_OK)

@mock.patch('mc_organization.api.viewsets.organization.Response')
@mock.patch('mc_organization.api.viewsets.organization.'
            'mc_organization.services.organization.suspend')
@mock.patch('mc_organization.api.viewsets.organization.ModelViewSet.get_serializer')
@mock.patch('mc_organization.api.viewsets.organization.OrganizationSuspendForm')
@mock.patch('mc_organization.api.viewsets.organization.ModelViewSet.get_object')
def test_viewset_suspend_action_with_valid_request_data(self, get_object_mock, form_mock, get_serializer_mock,
                                                        suspend_service_mock, response_mock):
    get_object_mock.return_value = self.organization
    form_mock.return_value.is_valid.return_value = True
    form_mock.return_value.cleaned_data.get.return_value = "suspend reason"
    get_serializer_mock.return_value = self.serialized_organization

    self.viewset.suspend(request=self.request, uuid=self.organization.uuid)

    self.assertEqual(get_object_mock.call_count, 1)
    form_mock.assert_called_once_with(data=self.request.data, organization=self.organization)
    suspend_service_mock.assert_called_once_with(
        organization=self.organization,
        reason=form_mock.return_value.cleaned_data.get.return_value
    )
    get_serializer_mock.assert_called_once_with(instance=self.organization)
    response_mock.assert_called_once_with(data=self.serialized_organization.data, status=status.HTTP_200_OK)

如果unsuspend动作单元测试花费的时间比更复杂的suspend动作单元测试长10倍, 我怎么能解决这个问题?

次要更新: 删除最慢的测试,作为unsuspend单元测试将使suspend单元测试成为最慢的测试:

0.0539s test_viewset_unsuspend_action (mc_organization.tests.api.viewsets.organization.test_u_viewset.OrganizationViewSetUnitTestCase)
0.0040s test_viewset_suspend_action_with_valid_request_data (mc_organization.tests.api.viewsets.organization.test_u_viewset.OrganizationViewSetUnitTestCase)

删除后:

0.0546s test_viewset_update_action_with_invalid_request_data (mc_organization.tests.api.viewsets.organization.test_u_viewset.OrganizationViewSetUnitTestCase)

什么可能导致这种情况并且是预期的行为?

0 个答案:

没有答案