Допустимо ли использовать "реальный" класс утилиты вместо издевательств в TDD?

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

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

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

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

Ответ 1

Правило не "издевается над всем", а "делает тесты простыми". Mocking следует использовать, если

  • Вы не можете создать экземпляр с разумными усилиями (читайте: вам нужен один вызов метода, но для создания экземпляра вам нужна рабочая база данных, соединение с БД и пять других классов).
  • Создание дополнительных классов дорого.
  • Дополнительные классы возвращают нестабильные значения (например, текущее время или первичные ключи из базы данных)

Ответ 2

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

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

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

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

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

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

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

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

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

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

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

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