Тестування в Джанго


12

Мені дуже важко писати ефективні одиничні тести для великого проекту 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правильно фільтрувати / агрегувати, щоб отримати правильний результат?

Знущання над timetime.now () є досить простим, але як я можу висміяти решту поведінки?

  • Я міг би використовувати світильники, але я чув про плюси і мінуси використання світильників для створення моїх даних (погана ремонтопридатність - це хитрощі, яка для мене вражає будинок).
  • Я також міг налаштувати свої дані через ORM, але це може бути обмежувати, тому що тоді я також повинен створювати пов'язані об'єкти. І ОРМ не дозволяє вам возитися з auto_now_addполями вручну.
  • Знущання над ORM - це ще один варіант, але не лише хитромудріти глубоко вкладені методи ORM, але логіка коду ORM висміюється з тесту, і глузування, здається, робить тест справді залежним від внутрішніх та залежних умов функція під тестом.

Найсильнішими гайками, які мають зламати, є такі функції, які сидять на декількох шарах моделей і функцій нижнього рівня і дуже залежать від часу, хоча ці функції можуть бути не надто складними. Моя загальна проблема полягає в тому, що як би я не виглядав нарізати, мої тести виглядають набагато складніше, ніж те, що вони тестують.


Спершу слід писати одиничні тести, це допоможе вам виявити проблеми у встановленні конструкції перед тим, як записати фактичний виробничий код.
Chedy2149

2
Це корисно, але насправді не вирішує питання про те, як найкраще протестувати притаманні справжньому, важким для ORM додатків.
acjay

Ви повинні абстрагуватися від шару стійкості
Chedy2149

1
Звучить чудово гіпотетично, але, що стосується технічного обслуговування проектів, я думаю, що для вставки шару постійної стійкості між діловою логікою та надзвичайно добре задокументованим Django ORM є нетривіальна вартість. Несподівано заняття набиваються купою крихітних посередницьких методів, які самі потребують відновлення з часом. Але, можливо, це виправдано в тих місцях, де довіра є критичною
acjay

Оформити замовлення: vimeo.com/43612849 і це: vimeo.com/15007792
Chedy2149

Відповіді:


6

Я збираюся йти вперед і зареєструвати відповідь на те, що я придумав до цього часу.

Моя гіпотеза полягає в тому, що для функції з глибоким зчепленням і станом реальність полягає в тому, що для її простору потрібно взяти багато ліній.

Ось як приблизно виглядає мій тест, спираючись на стандартну бібліотеку Mock:

  1. Я використовую стандартний ORM для налаштування послідовності подій
  2. Я створюю власний старт datetimeі підриваю auto_now_addчас, щоб відповідати фіксованій шкалі мого дизайну. Я подумав, що ОРМ не дозволяє цього, але це працює чудово.
  3. Я переконуюсь, що функція під тестом використовує from datetime import datetimeтак, що я можу виконувати виправлення datetime.now()лише у цій функції (якщо я знущаюся над усім datetimeкласом, ORM підходить).
  4. Я створюю власну заміну для object.key_method()простого, але чітко визначеного функціоналу, який залежить від аргументів. Я хочу, щоб це залежало від аргументів, бо в іншому випадку я не можу знати, чи працює логіка тестуваної функції. У моєму випадку вона просто повертає кількість секунд між startTimeі endTime. Я закріплюю object.key_method()його, new_callableзагортаючи в лямбду і безпосередньо перекладаючи на використання kwarg patch.
  5. Нарешті, я випускаю ряд тверджень на різних викликах summaryз різними аргументами, щоб перевірити рівність із очікуваними вручну обчисленими результатами, враховуючи дану поведінку макетаkey_method

Потрібно сказати, що це значно довше і складніше, ніж сама функція. Це залежить від БД, і насправді не відчувається як одиничний тест. Але він також досить відокремлений від внутрішніх функцій - лише її підпису та залежності. Тож я думаю, що це все-таки може бути тест одиниці.

У моєму додатку ця функція є досить важливою і підлягає рефакторингу для оптимізації її роботи. Тож я думаю, що біда того варта, незважаючи на складність. Але я все ще відкритий до кращих ідей, як до цього підійти. Це все моє довге подорож до більш тестового стилю розвитку ...

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.