Простой модульный тест Django занимает в 10 раз больше времени, чем несколько более сложный модульный тест - PullRequest
0 голосов
/ 15 мая 2018

Я работаю над некоторыми простыми юнит-тестами в Django==1.11 и python==2.7.12. Для всех подобных тестов время выполнения теста составляет около 0.0040 seconds, например, пользовательское действие suspend, которое включено в тест внизу поста. Все используемые классы, формы, вызываемые функции проверяются во всех тестах. Тем не менее, тест действия 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 действие юнит-теста займет почти в 10 раз больше времени, чем более сложное suspend действие юнит-теста, и как я мог решить это?

Незначительное обновление : Удаление самого медленного теста, будучи модульным тестом 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)

Что может вызвать это и это ожидаемое поведение?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...