2015-07-03 2 views
1

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

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

Многие люди используют подход, основанный на интерфейсе, в котором мне придется объявить интерфейс. Затем во время модульного тестирования мне придется предоставить реализацию интерфейса, который не работает с реальной базой данных.

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

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

Как с этим бороться?

+1

Это вопрос вкуса, я думаю. По моему опыту, дополнительное время, затрачиваемое на извлечение интерфейса, минимально по сравнению с уменьшенной сложностью модульных тестов. См. Также [this] (http://programmers.stackexchange.com/questions/159813/do-i-need-to-use-an-interface-when-only-one-class-will-ever-implement-it) обсуждение обмена программатором – Hintham

+3

только потому, что вы вводите интерфейс, это не значит, что вам нужен контейнер IoC внезапно. Контейнер IoC - это инструмент, который может помочь упростить построение графа сложного объекта, но это может ВСЕГДА быть сделано без контейнера. И в ваших модульных тестах вы должны создавать небольшие простые графические объекты (поскольку вы только тестируете небольшие единицы), вам не нужно использовать контейнер IoC для создания графиков объектов. Просто «новый» тестируемые объекты с издеваемыми зависимостями –

ответ

0

В общем, вы можете это сделать, но это зависит от того, какую насмешливую библиотеку вы используете. Для Moq вы можете просто использовать метод Setup для издевательского результата методов. Обычно, как вы сказали, что это prefferable использовать интерфейсы, но вы можете сделать это без интерфейсов:

c# - How do I mock a class without an interface?

В любом случае от архитектуры и потери зрения сочетания разумно использовать интерфейс подход Driven Development.

+0

Согласен. Но когда я знаю, что не будет другой реализации интерфейса, правильно ли вводить интерфейс и контейнер IoC и т. Д. Только для модульного тестирования? Зачем делать для этого реальный прикладной комплекс? – Learner

+0

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

0

Если вы не хотите, чтобы поразить вашу базу данных, вы в основном есть два варианта:

  • использовать альтернативную базу данных, возможно, in memory one.
  • Создайте некоторое разделение между собой и базой данных, как правило, издеваясь над взаимодействием.

С большинством насмешливых фреймворков (всех свободных) и ручных макетов, вы должны быть в состоянии предоставить ваш издеваемый экземпляр классу, который вы хотите проверить. Вы должны это сделать, независимо от того, вы издеваетесь над конкретным классом или с интерфейсом. Это делается путем инъекции зависимостей. По-видимому, общий консенсус заключается в том, что инъекция конструктора является предпочтительной, хотя инъекция свойств также является вариантом, если это то, что работает для вас.

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

public void SomeMethod(string someParam) { 
    var db = new SomeDbClass();  // Create db dependency 
    var job = new SomeDbClient(db); // Create class that uses db 
    job.SomeMethod(someParam);  // call some method... 
} 

Вы также можете просто использовать дефолт конструктор вроде этого:

public SomeDbClient(ISomeDependency dependency = null) { 
    if(dependency == null) { 
     dependency = new SomeDependency(); 
    } 
    _dependency = dependency; 
} 

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

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