2016-07-05 53 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)。实际上,使用第一个object.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(); 
     } 

这是可行的,但我不希望实现等于满足检验因为它会有所有其他的暗示在这里不值得一提。

我要的是一个比较器做同样的一个第二断言行:

data.ShouldBeEquivalentTo(expectedResult); 

但这不是每默认支持。

那么,我该如何解决这个问题。 谢谢。

回答

1

NSubstitute没有在时刻(1.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

如果我已经知道了结果,那么我就不必去测试它了,对:-)很明显,在现实世界中,我不知道什么是方法 - 即调用另一种方法,也许调用另一种方法 - 将交付给该方法,这就是为什么我测试我期望它接收什么参数。 –