Я действительно изо всех сил пытаюсь написать эффективные модульные тесты для большого проекта Django. У меня достаточно хорошее тестовое покрытие, но я понял, что написанные мною тесты - это, безусловно, интеграционные / приемочные тесты, а не модульные тесты, и у меня есть критические части моего приложения, которые не тестируются эффективно. Я хочу исправить это как можно скорее.
Вот моя проблема. Моя схема глубоко реляционная и в значительной степени ориентирована на время, что дает моему объекту модели высокую внутреннюю связь и множество состояний. Многие из моих методов модели запрашивают на основе временных интервалов, и я много работаю auto_now_add
в полях с метками времени. Итак, возьмем метод, который выглядит следующим образом:
def summary(self, startTime=None, endTime=None):
# ... logic to assign a proper start and end time
# if none was provided, probably using datetime.now()
objects = self.related_model_set.manager_method.filter(...)
return sum(object.key_method(startTime, endTime) for object in objects)
Как подходить к тестированию чего-то подобного?
Вот где я так далеко. Мне приходит в голову, что объекту модульного тестирования нужно дать какое-то насмешливое поведение by key_method
в своих аргументах, summary
правильно ли фильтрует / агрегирует для получения правильного результата?
Насмешка datetime.now () достаточно проста, но как я могу издеваться над остальным поведением?
- Я мог бы использовать приборы, но я слышал о плюсах и минусах использования приборов для построения моих данных (плохая ремонтопригодность - это мошенничество, которое мне кажется удачным).
- Я мог бы также настроить свои данные через ORM, но это может быть ограничением, потому что тогда я должен также создавать связанные объекты. И ORM не позволяет вам связываться с
auto_now_add
полями вручную. - Пересмешивание ORM - это еще один вариант, но не только непросто смоделировать глубоко вложенные методы ORM, но и логика в коде ORM исключается из теста, и, похоже, пересмотр делает тест действительно зависимым от внутренних компонентов и зависимостей функция-под-теста.
Кажется, что самые крепкие орешки - это такие функции, которые расположены на нескольких уровнях моделей и функций более низкого уровня и очень зависят от времени, даже если эти функции могут быть не очень сложными. Моя общая проблема заключается в том, что независимо от того, как я это делаю, мои тесты выглядят намного сложнее, чем те функции, которые они тестируют.
источник
Ответы:
Я собираюсь пойти дальше и зарегистрировать ответ на то, что я до сих пор придумал.
Моя гипотеза заключается в том, что для функции с глубокой связью и состоянием реальность такова, что для ее внешнего контекста просто потребуется много строк.
Вот как примерно выглядит мой контрольный пример, опираясь на стандартную библиотеку Mock:
datetime
и смещаюauto_now_add
время, чтобы соответствовать фиксированному графику моего проекта. Я думал, что ORM этого не допустил, но работает нормально.from datetime import datetime
чтобы я мог исправитьdatetime.now()
только эту функцию (если я высмеиваю весьdatetime
класс, ORM подгоняет).object.key_method()
, с простой, но четко определенной функциональностью, которая зависит от аргументов. Я хочу, чтобы это зависело от аргументов, потому что иначе я мог бы не знать, работает ли логика тестируемой функции. В моем случае он просто возвращает количество секунд междуstartTime
иendTime
. Я исправляю это, оборачивая его в лямбду и исправляя непосредственно кobject.key_method()
использованиюnew_callable
kwarg ofpatch
.summary
утверждений по различным вызовам с разными аргументами, чтобы проверить равенство с ожидаемыми вычисленными вручную результатами с учетом заданного поведения макета.key_method
Излишне говорить, что это значительно дольше и сложнее, чем сама функция. Это зависит от БД и не похоже на юнит-тест. Но он также довольно не связан с внутренними элементами функции - только ее сигнатура и зависимости. Поэтому я думаю, что на самом деле это может быть модульное тестирование.
В моем приложении эта функция достаточно важна и требует рефакторинга для оптимизации ее производительности. Так что я думаю, что проблема того стоит, несмотря на сложность. Но я все еще открыт для лучших идей о том, как подойти к этому. Вся часть моего долгого пути к более ориентированному на тестирование стилю разработки ...
источник