Я работаю над некоторыми простыми юнит-тестами в 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)
Что может вызвать это и это ожидаемое поведение?