2014-10-20 5 views
2

Я реализую шаблон репозитория класса запросов и тестирование с использованием NSubstitute.NSubstitute не соответствует Linq Expression

Repository интерфейс:

public interface IMyRepository 
{ 
    IQueryable<T> Query<T>(Expression<Func<T, bool>> filter) where T : class; 
} 

DateTimeProvider интерфейс:

public interface IMyDateTimeProvider 
{ 
    DateTime GetDateNow(); 
} 

интерфейс Применение: осуществление

public interface IMyApplication 
{ 
    List<Thing> GetThingsByQuery(int status); 
} 

Применение:

public class MyApplication : IMyApplication 
{ 
    private readonly IMyRepository myRepository; 

    private readonly IMyDateTimeProvider myDateTimeProvider; 

    public MyApplication(IMyRepository myRepository, IMyDateTimeProvider myDateTimeProvider) 
    { 
     this.myRepository = myRepository; 
     this.myDateTimeProvider = myDateTimeProvider; 
    } 

    public List<Thing> GetThingsByQuery(int status) 
    { 
     var createdDate = this.myDateTimeProvider.GetDateNow(); 

     return this.myRepository.Query<Thing>(t => t.CreatedDate == createdDate && t.Status == status).ToList(); 
    } 
} 

Тест:

[TestClass] 
public class ApplicationTest 
{ 
    private IMyApplication myApplication; 

    private IMyDateTimeProvider myDateTimeProvider; 

    private IMyRepository myRepository; 

    [TestMethod] 
    public void QueriesRepository() 
    { 
     // Arrange 
     var createdDate = new DateTime(2014, 1, 1); 

     this.myDateTimeProvider.GetDateNow().Returns(createdDate); 

     const int Status = 1; 

     // Act 
     this.myApplication.GetThingsByQuery(Status); 

     // Assert 
     this.myRepository.Received().Query<Thing>(t => t.CreatedDate == createdDate && t.Status == Status); 
    } 

    [TestInitialize] 
    public void TestInitialize() 
    { 
     this.myRepository = Substitute.For<IMyRepository>(); 

     this.myDateTimeProvider = Substitute.For<IMyDateTimeProvider>(); 

     this.myApplication = new MyApplication(this.myRepository, this.myDateTimeProvider); 
    } 
} 

Но тест не пройден со следующим сообщением:

NSubstitute.Exceptions.ReceivedCallsException: Expected to receive a call matching: 
    Query<Thing>(t => ((t.CreatedDate == value(MySolution.Test.ApplicationTest+<>c__DisplayClass0).createdDate) AndAlso (t.Status == 1))) 
Actually received no matching calls. 
Received 1 non-matching call (non-matching arguments indicated with '*' characters): 
    Query<Thing>(*t => ((t.CreatedDate == value(MySolution.Application.MyApplication+<>c__DisplayClass0).createdDate) AndAlso (t.Status == value(MySolution.Application.MyApplication+<>c__DisplayClass0).status))*) 

DateTime и статус в настоящее время разбирается в value(), которые отличаются между приложением и испытания.

Почему это? Как я могу это исправить?

ответ

0

Comparer равенство по умолчанию для выражения используется (ссылочное равенство):

например, выражение (t => t.CreatedDate == createdDate && t.Status == Status``) в:

this.myRepository.Received().Query<Thing>(t => t.CreatedDate == createdDate 
              && t.Status == Status   ); 

ли другой экземпляр для выражения в:

return this.myRepository.Query<Thing>(t => t.CreatedDate == createdDate 
             && t.Status == status   ).ToList(); 

Чтобы исправить проверить этот метод вызова проверить argument matchers within NSubstitute.

Но как пример:

Func<Expression<Thing, bool>, bool> validator = 
    // TODO this needs to be written properly, based on the expression, 
    // not its string representation 
    e => e.Body.ToString() == "t.CreatedDate == createdDate 
     && t.Status == Status"; 
this.myRepository.Received().Query<Thing>(Arg.Is<Expression<Thing, bool>>(validator)); 
+0

Я не уверен, как это реализовать. Я попытался 'this.myRepository.Received() Запрос (т => t.CreatedDate == Arg.Any () && t.Status == Arg.Any ());. И' this.myRepository. . Полученные() Запрос (т => t.CreatedDate == Arg.Is (createdDate) && t.Status == Arg.Is (Status)) ', но и по-прежнему использует' значения() 'и отсутствие – Shevek

+0

@ Shevek Отвечено обновлено –

+0

Я не смог получить ваш пример для компиляции.Это компилируется, но тест не выполняется с той же ошибкой: 'Expression > validator = t => t.CreatedDate == createdDate && t.Status == Статус;' и 'this.myRepository.Received(). Запрос (Arg.Is >> (валидатор)); ' – Shevek

1

Для усложнять выражений, если часто бывает проще утверждать на захваченных аргументов, используя callbacks чем с Received(). Пример (неполный):

Expression<Func<Thing, bool>> receivedFilter receivedFilter = null; 
myRepository.When(x => x.Query<Thing>(Arg.Any<...>)) 
    .Do(x => receivedQuery = x.Arg<Expression<Func<Thing, bool>>>()); 

Затем утвердите на захваченное выражение фильтра. Это может на самом деле проще просто выполнить фильтр FUNC Выражение (см, например, here)

Func<Thing, bool> predicate = receivedFilter.Compile(); 
var matchingThing = new Thing 
    { CreatedDate = createdData, Status = Status }; 
// assert matching 
predicate(matchingThing).Should().BeTrue(); 

// assert non.matching 
predicate(nonMatchingThing).Should().BeFalse(); 

Этот подход, кажется, делает тест немного больше черного боксировал, но это в общем не плохо.

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

  • Нет связанных вопросов^_^