NSubstitute,对收到的调用断言,使用 object.ReferenceEquals 比较参数
NSubstitute, assert on received calls, arguments is compared using 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 比较参数,并且由于我通常无法控制传递给方法的数据,因此对象(数据和 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 来满足测试,因为它会产生各种其他含义,这里不值得一提。
我想要的是一个比较器,对第二个断言行做同样的事情:
data.ShouldBeEquivalentTo(expectedResult);
但默认情况下不支持。
那么,我该如何解决这个问题。
谢谢。
您可以存储通过的内容,稍后再进行比较:
[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);
}
NSubstitute 目前没有对此的完全支持 (v1.10)。 Issue 160 对此进行了一些讨论。
David Osborne 提到的一个选择是捕获参数并使用您选择的断言库对它们进行断言。
另一种是使用自定义参数匹配器。我已经包含了一个来自 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) { ... }
如评论中所述,这可行,但在失败时会提供非常糟糕的错误消息。
我遇到了同样的问题,这个为我解决了:
[Test]
public void TestSample()
{
//Arrange
IDomainClass testingClass = Substitute.For<IDomainClass>();
IDomainClass data = new DomainClass() { A = 123, };
//Act
testingClass.CalledMethod(data);
//Assert
testingClass.Received(1).CalledMethod(Arg.Is<DomainClass>(x => x.A == 123)); //this worked for me
}
请看下面的示例:
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 比较参数,并且由于我通常无法控制传递给方法的数据,因此对象(数据和 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 来满足测试,因为它会产生各种其他含义,这里不值得一提。
我想要的是一个比较器,对第二个断言行做同样的事情:
data.ShouldBeEquivalentTo(expectedResult);
但默认情况下不支持。
那么,我该如何解决这个问题。 谢谢。
您可以存储通过的内容,稍后再进行比较:
[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);
}
NSubstitute 目前没有对此的完全支持 (v1.10)。 Issue 160 对此进行了一些讨论。
David Osborne 提到的一个选择是捕获参数并使用您选择的断言库对它们进行断言。
另一种是使用自定义参数匹配器。我已经包含了一个来自 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) { ... }
如评论中所述,这可行,但在失败时会提供非常糟糕的错误消息。
我遇到了同样的问题,这个为我解决了:
[Test]
public void TestSample()
{
//Arrange
IDomainClass testingClass = Substitute.For<IDomainClass>();
IDomainClass data = new DomainClass() { A = 123, };
//Act
testingClass.CalledMethod(data);
//Assert
testingClass.Received(1).CalledMethod(Arg.Is<DomainClass>(x => x.A == 123)); //this worked for me
}