2010-06-17 6 views
6

Я тестирую модуль ICustomerRepository, используемый для извлечения объектов типа Customer.Какова цель модульного тестирования репозитория интерфейса

  • В качестве единицы измерения, какое значение я получаю путем тестирования ICustomerRepository таким образом?
  • При каких условиях не удалось выполнить тест ниже?
  • Для тестов такого характера целесообразно проводить тесты, которые, как я знаю, должны терпеть неудачу? т.е. ищет идентификатор 4, когда я знаю, что я только помещен 5 в хранилище

Я, вероятно, отсутствует что-то очевидное, но, кажется, интеграционные тесты класса, реализующего ICustomerRepository будет иметь большую ценность.

[TestClass] 
public class CustomerTests : TestClassBase 
{ 
    private Customer SetUpCustomerForRepository() 
    { 
     return new Customer() 
     { 
      CustId = 5, 
      DifId = "55", 
      CustLookupName = "The Dude", 
      LoginList = new[] 
      { 
       new Login { LoginCustId = 5, LoginName = "tdude" }, 
       new Login { LoginCustId = 5, LoginName = "tdude2" } 
      } 
     }; 
    } 

    [TestMethod] 
    public void CanGetCustomerById() 
    { 
     // arrange 
     var customer = SetUpCustomerForRepository(); 
     var repository = Stub<ICustomerRepository>(); 

     // act 
     repository.Stub(rep => rep.GetById(5)).Return(customer); 

     // assert 
     Assert.AreEqual(customer, repository.GetById(5)); 
    } 
} 

Тест Базовый класс

public class TestClassBase 
{ 
    protected T Stub<T>() where T : class 
    { 
     return MockRepository.GenerateStub<T>(); 
    } 
} 

ICustomerRepository и IRepository

public interface ICustomerRepository : IRepository<Customer> 
{ 
    IList<Customer> FindCustomers(string q); 
    Customer GetCustomerByDifID(string difId); 
    Customer GetCustomerByLogin(string loginName); 
} 

public interface IRepository<T> 
{ 
    void Save(T entity); 
    void Save(List<T> entity); 
    bool Save(T entity, out string message); 
    void Delete(T entity); 
    T GetById(int id); 
    ICollection<T> FindAll(); 
} 

ответ

5

Правило № 1 испытания:

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

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

Что такое заглушка?

Штыри используются для предоставления консервированных значений для управления некоторыми аспектами тестируемого класса. Например. Скажем, у вас есть CustomerService, у которого есть экземпляр типа ICustomerRepository. Если вы хотите увидеть, что CustomerService может изящно обрабатывать случай ошибки, когда репозиторий пуст, вы должны заглушить метод GetCustomerById, чтобы вернуть ничего/null/исключить исключение, а затем убедиться, что метод CustomerService сделал правильную вещь (например, вернуть результат не найденному клиенту).

I.e. заглушка - это просто сотрудник, который помогает вам достичь определенного состояния/поведения, представляющего интерес. Мы тестируем CustomerService, а заглушка ICustomerRepository просто помогает нам достичь нашей цели.

Вы не первый, кто задал этот вопрос :). Обычно я советую разработчикам hand-roll their test doubles at first. Это помогает понять все взаимодействия и то, что структура действительно делает для вас.

4

Интерфейсы, по определению, только контракты, так что нет никакого кода для тестирования. Вы хотите написать модульные тесты против конкретной реализации (ов) интерфейса, потому что именно там живет реальный код исполнения.

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

6

Возможно, мне что-то не хватает, но кажется, что каждый аспект вашего теста издевается?

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

Например, вы можете макетировать репозиторий клиентов, чтобы вы могли вызвать метод, который проверяет логин пользователя. Вы использовали бы ваш mock-репозиторий, чтобы ваш блок-тест не мог полагаться на настоящий источник данных, а не на проверку вашего макетного репозитория.

2

Ваш тест не имеет для меня никакого смысла. Вы тестируете, если запрограммированный заглушка возвращает значения, которые вы его подаете, вы не проверяете какой-либо реальный код.

Следуйте за ответом dcp. Интерфейс - это объявление методов. Вы должны проверить их реализацию.

+0

Как? Всюду, где я читаю, нас учат фальсифицировать интерфейс для нашего модульного теста. Как мы можем протестировать конкретную реализацию? Я думал, что этого следует избегать до моего понимания. Не могли бы вы привести пример? Спасибо! – Stack0verflow

+1

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

+1

Глупый пример: интерфейс «Eater» для вещей, которые «едят», реализуемые «Dog» и вызываемые «мастером» в методе «feed (Eater pet)». Когда вы проверите 'Собака', вы проверите ее реализацию интерфейса« Eater », вызвав« eat »на экземпляр собаки и посмотрите, например. что собака получает вес. Когда вы проверяете метод '' '' '' '' '' '' '' '' '' '' '' '' '' '' ', вы создаете mock' Eater', передаете его этому методу и проверяете, что 'eat' был вызван на него. –

Смежные вопросы