Допустимо ли использовать «настоящий» класс утилит вместо насмешек в TDD? - PullRequest
11 голосов
/ 05 ноября 2010

У меня есть проект, с которым я пытаюсь научиться модульному тестированию и методам TDD. Я обнаружил, что попадаю в довольно запутанные случаи, когда трачу много времени на настройку макетов для служебного класса, который используется практически везде.

Из того, что я читал о модульном тестировании, если я тестирую MyClass, я должен издеваться над любой другой функциональностью (например, предоставляемой UtilityClass). Допустимо ли (если предположить, что сам UtilityClass имеет полный набор тестов) просто использовать UtilityClass, а не настраивать макеты для всех различных тестовых случаев?

Редактировать: одна из вещей, для которых я много настраиваю. Я моделирую карту с различными объектами в разных местах. Одним из распространенных методов в моем служебном классе является GetDistanceBetween. Я тестирую методы, которые влияют на вещи в зависимости от их индивидуальных свойств, поэтому, например, тест, который выбирает все объекты в пределах 5 единиц точки и возраст старше 3, потребует несколько тестов (получает старые объекты в диапазоне, игнорирует старые объекты диапазона, игнорирует молодые объекты в диапазоне, корректно работает с коэффициентами, кратными каждому случаю), и все эти тесты нуждаются в настройке метода GetDistanceBetween. Умножьте это на каждый метод, который использует GetDistanceBetween (почти на каждый), и на разные результаты, которые метод должен возвращать в различных обстоятельствах, и это требует много настроек.

Я вижу, что по мере дальнейшего развития этого процесса, может быть больше вызовов классов утилит, большое количество объектов и много настроек для этих классов фиктивных утилит.

Ответы [ 5 ]

23 голосов
/ 05 ноября 2010

Правило не "издеваться над всем", а "делать тесты простыми". Насмешка должна использоваться, если

  1. Нельзя создать экземпляр с разумными усилиями (читай: вам нужен один вызов метода, но для создания экземпляра вам нужна рабочая база данных, соединение с БД и пять других классов).
  2. Создание дополнительных классов стоит дорого.
  3. Дополнительные классы возвращают нестабильные значения (например, текущее время или первичные ключи из базы данных)
9 голосов
/ 05 ноября 2010

TDD на самом деле не о тестировании. Его главное преимущество заключается в том, чтобы помочь вам создать чистый, простой в использовании код, который могут понять и изменить другие люди. Если его основным преимуществом было тестирование, то вы могли бы писать тесты после кода, а не раньше, с большей частью того же эффекта.

Если вы можете, я рекомендую вам перестать думать о них как о «модульных тестах». Вместо этого думайте о своих тестах как о примерах использования своего кода вместе с описаниями его поведения, которые показывают, почему ваш код является ценным.

Как часть этого поведения, ваш класс может захотеть использовать несколько сотрудничающих классов. Вы можете издеваться над ними.

Если ваши служебные классы являются основной частью поведения вашего класса, и ваш класс не имеет значения или его поведение не имеет смысла без них, то не смейтесь над ними.

Ответ Аарона Дигуллы довольно хороший; Я бы перефразировал каждый из его ответов в соответствии с этими принципами:

  1. Поведение сотрудничающего класса является сложным и не зависит от поведения интересующего вас класса.

  2. Создание сотрудничающего класса не является ценным аспектом вашего класса и не должно быть частью ответственности вашего класса.

  3. Сотрудничающий класс предоставляет контекст, который меняет поведение вашего класса и, следовательно, играет на примерах того, как вы можете его использовать и какое поведение вы можете ожидать.

Надеюсь, это имеет смысл! Если вам понравилось, посмотрите на BDD, который использует этот вид словаря гораздо больше, чем «тест».

4 голосов
/ 05 ноября 2010

Теоретически вы должны пытаться высмеивать все зависимости, но на самом деле это никогда не возможно. Например. Вы не собираетесь издеваться над основными классами из стандартной библиотеки. В вашем случае, если служебный класс просто содержит несколько базовых вспомогательных методов, я думаю, я бы не стал его издеваться.

Если это сложнее или подключается к каким-то внешним ресурсам, вы должны поиздеваться над этим. Вы можете подумать о создании выделенного класса конструктора макетов, который создаст стандартный макет (с определенными стандартными заглушками и т. Д.), Чтобы избежать дублирования насмешливого кода во всех классах тестирования.

2 голосов
/ 05 ноября 2010

Нет, это неприемлемо, потому что вы больше не тестируете класс изолированно, что является одним из наиболее важных аспектов модульного теста. Вы тестируете его с зависимостью от этой утилиты, даже если утилита имеет собственный набор тестов. Чтобы упростить создание макетов объектов, вы можете использовать макет фреймворка. Вот несколько популярных вариантов:

Конечно, если этот служебный класс является закрытым и может использоваться только в рамках тестируемого класса, тогда вам не нужно его высмеивать.

1 голос
/ 05 ноября 2010

Да, это приемлемо. Важно, чтобы UtilityClass тщательно тестировал модули и имел возможность различать, если тест не пройден из-за тестируемого класса или из-за UtilityClass.

Тестирование класса в отдельности означает тестирование его в контролируемой среде, в среде, в которой можно контролировать поведение объектов.
Необходимость создания слишком большого количества объектов в тестовой установке является признаком того, что среда становится слишком большой и, следовательно, недостаточно контролируется. Пришло время вернуться к издевательским объектам.

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