2016-07-05 1 views
1

Пожалуйста, обратите внимание на следующий пример:NSubstitute, утверждают о принятых вызовах, аргументы сравниваются с помощью object.ReferenceEquals

public interface IDomainClass 
    { 
     int A { get; set; } 
     void CalledMethod(IDomainClass data); 
    } 
    public class DomainClass : IDomainClass 
    { 
     public int A { get; set; } 

     public void CalledMethod(IDomainClass data) 
     { 
      throw new NotImplementedException(); 
     } 
    } 

И следующий тест:

[Test] 
    public void TestSample() 
    { 
     //Arrange 
     IDomainClass testingClass = Substitute.For<IDomainClass>(); 

     IDomainClass data = new DomainClass() { A = 123, }; 
     IDomainClass expectedResult = new DomainClass() { A = 123, }; 

     //Act 
     testingClass.CalledMethod(data); 

     //Assert 
     testingClass.ReceivedWithAnyArgs(1).CalledMethod(null); //ok 
     data.ShouldBeEquivalentTo(expectedResult);    //ok 
     testingClass.Received(1).CalledMethod(expectedResult); //fail 
    } 

Проблема заключается в том, что я не знаю, как проверить аргументы в полученном вызове (CallMethod). Как бы то ни было, аргументы сравниваются с использованием первого объекта .ReferenceEquals, а затем object.Equals, и поскольку я обычно не контролирую доставленные данные методу, объекты (data и expectedResult) никогда не ссылаются на один и тот же объект.

Однако, есть способ, чтобы заставить его работать, и что если я переопределить Equals, как это:

 public override bool Equals(object obj) 
     { 
      return this.A.Equals((obj as DomainClass).A); 
     } 
     public override int GetHashCode() 
     { 
      return this.A.GetHashCode(); 
     } 

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

То, что я хочу, сравнивающий делать то же самое на второй линии Assert:

data.ShouldBeEquivalentTo(expectedResult); 

Но это не поддерживается по-умолчанию.

Итак, как решить эту проблему. Спасибо.

ответ

1

NSubstitute не полностью запеченную поддержки для этого в данный момент (v1.10). Issue 160 обсуждает это.

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

Другим является использование настраиваемого аргумента. Я включил пример из this comment:

[Test] 
public void UsingArgMatcher() { 
    var repos = Substitute.For<IRepos>(); 

    var sut = new SomeService(repos); 
    sut.Process(); 

    repos.Received().Save(Arg.Is(EquivalentTo(new int[] { 1, 2, 3 }))); 
} 

private Expression<Predicate<IEnumerable<T>>> EquivalentTo<T>(IEnumerable<T> enumerable) { 
    return x => Equiv(enumerable, x); 
} 

private bool Equiv<T>(IEnumerable<T> a, IEnumerable<T> b) { ... } 

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

Существует также пример hooking NSubstitute up to FluentAssertions.

+0

Ну, я согласен, сообщение об ошибке не очень красивое, но это обход и будет делать пока пока не будет выпущена лучшая реализация ... –

0

Вы можете сохранить то, что прошло, а затем сравнить позже:

[Test] 
public void TestSample() 
{ 
    //Arrange 
    IDomainClass testingClass = Substitute.For<IDomainClass>(); 

    IDomainClass data = new DomainClass() { A = 123, }; 

    IDomainClass methodReceievedThis = null; 

    testingClass 
     .When(t => t.CalledMethod(Arg.Any<IDomainClass>()) 
     .Do(p => methodReceievedThis = p); 

    //Act 
    testingClass.CalledMethod(data); 

    //Assert 
    testingClass.ReceivedWithAnyArgs(1).CalledMethod(null); //ok 

    methodReceievedThis.ShouldBeEquivalentTo(data); 
} 
+0

Это правда, но я все равно не знаю, получил ли CalledMethod вызов с точными аргументами или нет, правильно ...! –

+0

В контексте теста, который вы выполняете, потому что 'methodReceivedThis' может быть установлен только вызовом' CalledMethod() '. –

+0

Если бы я уже знал результат, то мне бы не пришлось его проверять, правильно :-) Очевидно, что в реальном мире я не знаю, какой метод, который вызывает другой метод, который может вызвать еще один метод - будет доставлять этот метод, и именно поэтому я проверяю, какие аргументы я бы ожидал получить. –

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