2014-02-25 3 views
0

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

Вопрос 1: Я использую ASP MVC4 и хочу использовать Moq с моим блоком тестирования. После прочтения есть много примеров, я вижу, что у меня есть интерфейс. Где именно это нужно? В папке контроллера тестовый проект?

Вопрос 2 Если я тестирую метод в моем контроллере и имеет несколько вызовов БД, как бы я MOq что

public ActionResult Index() 
{ 
var model = new myModel(); 
var pList = new List<myModel.pType>(); 
var sList = new List<myModel.sType>(); 
var results = Class1.FetchPData(); // how would I mock this 
var result1 = Class1.FetchSData(); // how would I mock this 

for (int i = 0; i < results.Count(); i++) 
{ 
    ... do stuff 
} 


for (int j = 0; j < result1.Count(); j++) 
{ 
    ..do stuff 
} 

    return View("Index", model); 
} 

Должен ли я создать еще один способ, в котором он содержит то же самое логики, но мне придется передать «Mock Object» в качестве параметра для метода и использовать это как реализуемый метод в моем интерфейсе? Или переустановите мой метод?

ответ

2

После прочтения есть много примеров, я вижу, что я полагаю, что у есть интерфейс. Где именно это нужно? В папке контроллера , тестовом проекте?

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

Если я тестирую метод в моем контроллере и имеет несколько вызовов децибела, как бы я MOq что

Помните, что хорошие модульные тесты должны быть быстро, Isolated, Повторяется, Само- Проверка и своевременность (FIRST). Наличие вызовов базы данных в контроллере не позволяет быстро запускать тесты (вызовы базы данных очень медленные по сравнению с кодом в памяти), чтобы изолировать тестовый контроллер и делать тесты всегда повторяемыми. Также ваш контроллер просто выполняет многие действия (т. Е. Нарушает принцип SRP) - он получает пользовательский ввод, выполняет запросы к базе данных и подготавливает модель для просмотра.

Итак, для того, чтобы отделить обязанности и сделать ваш контроллер проверяемым, вы должны связанными экстракта доступа к данным кода для отдельного класса (как правило, такие классы называются хранилищ). И создать абстракцию, которая будет указывать API между контроллером и хранилища:

public interface IYourRepository 
{ 
    IEnumerable<pType> FetchPData(); 
    IEnumerable<sType> FetchSData(); 
} 

Затем сделайте ваш контроллер зависит от этой абстракции (обратная зависимость), и впрыснуть хранилище на контроллер (можно использовать Ninject, Unity или другие рамки инъекции зависимостей) :

IYourRepository _repository; 

public YourController(IYourRepository repository) 
{ 
    _repository = repository; 
} 

public ActionResult Index() 
{ 
    var model = new myModel(); 

    foreach (var p in _repository.FetchPData()) 
     // do stuff 

    foreach (var s in _repository.FetchSData()) 
     // do stuff 


    return View("Index", model); 
} 

Это позволит издеваться хранилище легко и обеспечить высмеивал объект управления:

var repositoryMock = new Mock<IYourRepository>(); 
repositoryMock.Setup(r => r.FetchPData()).Returns(pList); 
repositoryMock.Setup(r => r.FetchSData()).Returns(sList); 

var controller = new YourController(repositoryMock.Object); 
var result = controller.Index(); 

// Assertions 
+0

ОК Я понимаю, знаю. Поэтому в будущем я должен написать свой метод так, чтобы его также можно было легко высмеивать. –

+0

Я должен упомянуть, что 'FetchPData' и' FetchSData' являются статическим методом actaully, вызываемым из другого класса. –

+0

@JackThor, даже после того, как вы редактировали вопрос, ответ тот же - сделайте их нестатичными и добавьте еще один экземпляр класса в контроллер. –