Подтвердить что ты не робот

Как бороться с чрезмерным использованием интерфейса в TDD?

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

public class SomeClass
{
    public SomeClass(IDependencyA first, IDependency second)
    {
        // ...
    }
}

В результате почти каждый класс будет реализовывать интерфейс.

Да, код будет развязан и может быть протестирован очень легко изолированно, но также будут дополнительные уровни косвенности, которые просто заставляют меня чувствовать себя немного... непросто. Что-то не так.

Может ли кто-нибудь использовать другие подходы, которые не требуют такого интенсивного использования интерфейсов?

Как поживают все ваши ребята?

4b9b3361

Ответ 1

В ваших тестах вам предлагается переделать ваши классы.

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

Например, вместо предоставления TaxCalculator с ITaxRateRepository (который попадает в базу данных во время CalculateTaxes), получите эти значения перед созданием экземпляра TaxCalculator и предоставьте их его конструктору:

// Bad! (If necessary on occasion)
public TaxCalculator(ITaxRateRepository taxRateRepository) {}

// Good!
public TaxCalculator(IDictonary<Locale, TaxRate> taxRateDictionary) {}

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

Для превосходного обзора методов снижения зависимости от зависимостей см. Макет устранения шаблонов.

Ответ 2

Не используйте интерфейсы! Большинство издевательских фреймворков могут издеваться над конкретными классами.

Ответ 3

То, что недостаток макетных тестов приближается. Это обсуждение проблемы границы, так как это насчет насмешек. Имея соотношение тестовых случаев 1:1 к классам домена, ваша граница теста очень мала. Результатом небольшой тестовой границы является распространение интерфейсов и тестов, которые зависят от них. Рефакторинг становится более сложным из-за количества взаимодействий, которые вы издеваетесь и заканчиваете. Путем тестирования кластеров классов с одним тестом рефакторинг становится проще, и вы используете меньше интерфейсов. Остерегайтесь, однако, что вы можете проверить слишком много классов сразу. Чем сложнее ваши классы, тем больше кодов, которые нужно протестировать. Это может привести к комбинаторному взрыву, и вы не можете проверить их все. Слушайте код и тесты, они сообщают вам что-то о вашем коде. Если вы видите, что сложность возрастает, возможно, самое подходящее время для внедрения нового тестового примера и интерфейса/реализации и издевательства над его оригиналом.

Ответ 4

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

Если SomeClass зависит от IDependencyA, IDependencyB и IDependencyC, это возможность увидеть, можно ли извлечь из логики, которую класс выполняет с этими тремя интерфейсами, в другой класс/интерфейс, IDependencyABC.

Затем, когда вы пишете свои тесты для SomeClass, вам нужно только высмеять логику, которую предоставляет IDependencyABC.

Кроме того, если вам все еще неудобно; возможно, это не интерфейс, который вам нужен. Например, классы, которые содержат состояние (параметры, передаваемые, например), возможно, просто будут созданы и переданы вместо них как конкретные классы. Ответ Джеффа ссылается на это, где он упоминает о том, чтобы переходить в ваш конструктор ТОЛЬКО, что вам нужно. Это обеспечивает меньшую связь между вашими конструкциями и является лучшим показателем намерений ваших потребностей. Просто будьте осторожны, проходя вокруг структур данных (IDictionary <, > ).

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