Тестирование кода, который зависит от Enterprise Library, даже если он не предоставляет интерфейсы? - PullRequest
5 голосов
/ 02 апреля 2012

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

ДляНапример, в документации по Enterprise Library 5.0 говорится об использовании контейнера Unity для создания экземпляров.В нем говорится, что это помогает «тестируемости: тривиально изолировать классы от зависимостей при использовании стиля внедрения зависимостей». MSDN

Как я могу использовать это в своих приборах для модульного тестирования?В их примере есть конструктор с параметрами в качестве классов, а не интерфейсов:

public class TaxCalculator 
{
  private ExceptionManager _exceptionManager;
  private LogWriter _logWriter;

  public TaxCalculator(ExceptionManager em, LogWriter lw) 
  {
    this._exceptionManager = em;
    this._logWriter = lw;
  }
}

Ответы [ 3 ]

9 голосов
/ 02 апреля 2012

Чтобы ответить на вопрос " Как мне проверить код Enterprise Library ": вы этого не сделаете. Тестирование чужих вещей - это работа других людей. Любые интерфейсы или абстракции в Enterprise Library или любой другой сторонней библиотеке существуют для их собственных целей абстракции, а не для ваших.

Что вам нужно сделать, это определить свои собственные интерфейсы, которые описывают потребности вашего приложения (ведение журнала, кэширование, шифрование и т. Д.), А затем написать адаптеры, которые реализуют ваши интерфейсы, используя Enterprise Library (или другие сторонние библиотеки). Эта практика известна как принцип обращения зависимостей .

Чтобы протестировать свой собственный код, разработанный таким образом, для тестов на уровне модулей / компонентов вы просто должны использовать Test Doubles для тех интерфейсов, которые вы определили сами (например, IMyOwnLogger). Чтобы протестировать написанные вами адаптеры для адаптации к сторонним библиотекам, вы должны написать интеграционные тесты. Чтобы проверить, что все это работает вместе, вы должны написать приемочные тесты, которые ведут приложение через пользовательский интерфейс или подкожно.

Для получения дополнительной информации об этом представлении ознакомьтесь с моей статьей: " Рекомендации TDD: не издевайтесь над другими ".

4 голосов
/ 02 апреля 2012

Желательно программировать против абстракции вместо реализации.Но абстракция не всегда интерфейс.Это может быть абстрактный класс.

public abstract class LogWriter
{
    public abstract void Write(string message);
}

Итак, нет проблем создать макет абстрактного класса:

Mock<LogWriter> logWriter = new Mock<LogWriter>();
TaxCalculator calc = new TaxCalculator(logWriter.Object);

Если вы не проводите юнит-тестирование, я не вижулюбая проблема для передачи неабстрактных параметров, из-за принципа YAGNI.Если мне не нужна другая реализация ExceptionManager, то зачем мне над ней создавать абстракцию?Но если я сделаю TDD, то мне определенно понадобятся как минимум две реализации класса.Один настоящий и один макет / заглушка.

Кстати, будьте осторожны с анти-паттерном сервисного локатора .

ОБНОВЛЕНИЕ: Не получилось, что вы ссылаетесь на существующие классы Microsoft.Practices.EnterpriseLibrary (что мне не нравится).Я думаю, что это очередной провал проекта команды Microsoft.Practices.Создание «запечатанного» класса ExceptionManager, который не реализует никаких интерфейсов / базовых классов, убивает тестируемость.

3 голосов
/ 02 апреля 2012

Пока ваши классы не sealed, компетентная среда моделирования может создать подкласс, который будет действовать точно так же, как и реализация макета интерфейса. Есть и другие соображения, которые необходимо учитывать, когда вы зависите от конкретных классов - методы sealed будут по-прежнему выполняться в указанном классе и т. Д. - но в общем случае ничем не отличается от зависимости от интерфейса.

...