Как бороться с чрезмерным использованием интерфейса в TDD? - PullRequest
21 голосов
/ 24 марта 2011

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

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

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

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

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

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

Ответы [ 4 ]

12 голосов
/ 24 марта 2011

Ваши тесты советуют вам перепроектировать ваши классы.

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

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

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

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

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

Превосходный обзор методов уменьшения зависимости от зависимостей см. В Шаблоны устранения пробелов .

5 голосов
/ 24 марта 2011

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

3 голосов
/ 24 марта 2011

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

1 голос
/ 24 марта 2011

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

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

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

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

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

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