2010-10-17 3 views
4

Я только начал играть с модульным тестированием/издевается, используя Moq, и столкнулся с проблемой ..C# + Mock сервисный уровень?

У меня есть сервисный слой под названием «CustomerService», которые следующий код:

public interface ICustomerService 
{ 
    Customer GetCustomerById(int id); 
} 

public class CustomerService : ICustomerService 
{ 
    private IRepository<Customer> customerRepository; 

    public CustomerService(IRepository<Customer> rep) 
    { 
     customerRepository = rep; 
    } 
    public Customer GetCustomerById(int id) 
    { 
     var customer = customerRepository.Get(x => x.CustomerId == id); 

     if (customer == null) 
      return null; 

     return customer; 
    } 
} 

Моего репозиторий класса является общим, и следующим:

public interface IRepository<T> : IDisposable where T : class 
    { 
     T Get(Expression<Func<T, bool>> predicate); 
    } 

    public class Repository<T> : IRepository<T> where T : class 
    { 
     private ObjectContext context; 
     private IObjectSet<T> objectSet; 

     public Repository() 
      : this(new demonEntities()) 
     { 
     } 

     public Repository(ObjectContext ctx) 
     { 
      context = ctx; 
      objectSet = context.CreateObjectSet<T>(); 
     } 

     public T Get(Expression<Func<T, bool>> predicate) 
     { 
      T entity = objectSet.Where<T>(predicate).FirstOrDefault(); 

      if (entity == null) 
       return null; 

      return objectSet.Where<T>(predicate).FirstOrDefault(); 
     } 

     public void Dispose() 
     { 
      Dispose(true); 
      GC.SuppressFinalize(this); 
     } 

     protected virtual void Dispose(bool disposing) 
     { 
      if (disposing) 
      { 
       if (context != null) 
       { 
        context.Dispose(); 
        context = null; 
       } 
      } 
     } 
    } 

Теперь мой вопрос .. Как я могу сделать модульное тестирование, чтобы проверить, возвращает ли мой GetCustomerById нуля или нет?

Уже пробовал:

[TestMethod] 
public void GetCustomerTest() 
{ 
    const int customerId = 5; 

    var mock = new Mock<IRepository<Customer>>(); 
    mock.Setup(x => x.Get(z => z.CustomerId == customerId)) 
     .Returns(new Customer()); 

    var repository = mock.Object; 
    var service = new CustomerService(repository); 
    var result = service.GetCustomerById(customerId); 

    Assert.IsNotNull(result); 
} 

без везения ...

+0

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

+0

уже пробовал, что без везения ... – ebb

ответ

5

Вам нужно сделать метод Repository<T>.Get виртуальным так Moq может переопределить его и возвращает значение, настроенное:

public virtual T Get(Expression<Func<T, bool>> predicate) 

и в тесте, изменить

mock.Setup(x => x.Get(z => z.CustomerId == customerId)) 
     .Returns(new Customer()); 

в

mock.Setup(x => x.Get(It.IsAny<Expression<Func<Customer, bool>>>())) 
     .Returns(new Customer()); 

, в котором говорится о возврате нового Customer для любого Expression<Func<Customer, bool>>. В идеале вы проверили бы конкретное выражение, но в соответствии с принятым ответом на этот вопрос SO question Moq не может этого сделать.

Если вы хотите, чтобы проверить, что ваш уровень обслуживания было ничего неожиданного в Customer возвращенного хранилище не делать, вместо тестирования, чтобы увидеть, что любогоCustomer был возвращен, вы можете настроить макет Customer (будучи уверенным сделать свойство CustomerId виртуальным) и утверждать, что возвращаемый сервисным словом номер Customer имел ожидаемые свойства.

[TestMethod] 
public void GetCustomerTest() 
{ 
    const int customerId = 5; 

    var mockCustomer = new Mock<Customer>(); 

    mockCustomer.SetupGet(x => x.CustomerId) 
     .Returns(customerId); 

    var mock = new Mock<IRepository<Customer>>(); 

    mock.Setup(x => x.Get(It.IsAny<Expression<Func<Customer, bool>>>())) 
     .Returns(mockCustomer.Object); 

    var repository = mock.Object; 
    var service = new CustomerService(repository); 
    var result = service.GetCustomerById(customerId); 

    Assert.AreEqual(customerId, result.CustomerId); 
} 

НТН

+0

Я получаю сообщение об ошибке в строке 22: «Метод тестирования MyApp.Test.Services.CustomerServiceTest.GetCustomerTest бросил исключение: System.ArgumentException: Неверная настройка для неперехваченного элемента: x => x.CustomerId" – ebb

+0

check чтобы убедиться, что CustomerId является виртуальным, тогда это должно быть нормально –

+0

, поэтому мне нужно отредактировать сгенерированный код из EF? – ebb

0

вы должны создать макет против интерфейса.

вы должны установить элемент в классе Ложная вместо Implementor

вам тогда нужно вызвать .Setup на макет, созданный для метода .. rememver использовать метод сцепления, чтобы сделать его проверяемый.

запустить метод в тесте, а затем вызвать mock.Verify()

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

+0

hmm .. это уже уже то, что я сделал atm (если вы посмотрите мой пост, я обновил еще какой-то код) ... – ebb

+0

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

0

Причина вы не можете сделать это, потому что один лямбда x => x.CustomerId == id не равен другому лямбда x => x.CustomerId == id так Moq не может сравниться с ними.

Однако, если у вас, скажем, класс с общими операциями на:

public class CustomerQueries { 
    public static Predicate<Customer> ById(int id) = x => x.CustomerId == id; 
} 

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

PS: Вы считаете, что используете Predicate<T> вместо Expression<Func<T, bool>>? Его легче читать и понимать цель.

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