我正在尝试使用NSubstitute模拟Substitute的返回值,但是由于方法签名使用的是Func,因此我无法获得替代方法来返回正确的值。
我已经看过这些问题,但是无法使其与我的Func一起使用。
Mocking Action<T> with NSubstitute
Mocking out expression with NSubstitute
我尝试模拟的接口(interface)是这样的(有点简单):
public interface IOrgTreeRepository<out T> where T : IHierarchicalUnit
{
T FirstOrDefault(Func<T, bool> predicate);
}
我用NSubstitute代替它,如下所示:
_orgTreeRepository = Substitute.For<IOrgTreeRepository<IOrganizationUnit>>();
然后,我尝试更改返回值,如下所示:
_orgTreeRepository.FirstOrDefault(Arg.Is<Func<IOrganizationUnit, bool>>(x => x.Id== _itemsToUpdate[0].Id)).Returns(existingItems[0]);
但是它只是返回一个代理对象,而不是我在existingItems中定义的对象。
但是,由于其他问题,我设法使它起作用,但对我没有帮助,因为我每次都需要特定的物品。
_orgTreeRepository.FirstOrDefault(Arg.Any<Func<IOrganizationUnit, bool>>()).Returns(existingItems[0]); // Semi-working
我猜它将lambda表达式视为一种绝对引用,因此跳过了它吗?有什么方法可以模拟返回值?
最佳答案
正如您正确猜测的那样,NSubstitute仅在此处使用引用相等,因此,除非您有对相同谓词的引用(有时是一个选择),否则您将必须匹配任何调用(Arg.Any
或.ReturnsForAnyArgs
)或使用近似的匹配形式检查传入的功能。
近似匹配的示例:
[Test]
public void Foo() {
var sample = new Record("abc");
var sub = Substitute.For<IOrgTreeRepository<Record>>();
sub.FirstOrDefault(Arg.Is<Func<Record,bool>>(f => f(sample))).Returns(sample);
Assert.AreSame(sample, sub.FirstOrDefault(x => x.Id.StartsWith ("a")));
Assert.AreSame(sample, sub.FirstOrDefault(x => x.Id == "abc"));
Assert.Null(sub.FirstOrDefault(x => x.Id == "def"));
}
在这里,我们将
FirstOrDefault
stub ,以便在sample
返回Func<T,bool>
的true
时返回sample
(这是使用Arg.Is
的另一种重载,该重载采用表达式,而不是传入的参数值)。这通过了两个不同谓词的测试,因为
sample
满足了两个条件。它还通过了最后一个断言,因为它不为检查其他id的函数返回sample
。我们不能保证在这种情况下使用了特定的谓词,但这可能就足够了。否则,我们会在Func上受到引用质量的困扰。希望这可以帮助。