来自 Func 和 NSubstitute 的模拟结果
Mock result from Func with NSubstitute
我正在尝试使用 NSubstitute 来模拟来自 Substitute 的 return 值,但是我无法获得 return 正确值的替代值,因为方法签名正在使用 Func。
我已经看到这些问题,但无法将其与我的 Func 一起使用。
Mocking out expression with NSubstitute
我尝试模拟的界面是这样的(有点简单):
public interface IOrgTreeRepository<out T> where T : IHierarchicalUnit
{
T FirstOrDefault(Func<T, bool> predicate);
}
我用 NSubstitute 代替它,如下所示:
_orgTreeRepository = Substitute.For<IOrgTreeRepository<IOrganizationUnit>>();
然后我尝试像这样更改 return 值:
_orgTreeRepository.FirstOrDefault(Arg.Is<Func<IOrganizationUnit, bool>>(x => x.Id== _itemsToUpdate[0].Id)).Returns(existingItems[0]);
但它只是 return 一个代理对象,而不是我在 existingItems 中定义的对象。
然而,多亏了其他问题,我设法让它工作,但这对我没有帮助,因为我每次都需要一个特定的项目。
_orgTreeRepository.FirstOrDefault(Arg.Any<Func<IOrganizationUnit, bool>>()).Returns(existingItems[0]); // Semi-working
我猜它把 lambda 表达式当作一种绝对引用,因此跳过它?有什么办法可以模拟 return 值吗?
正如您猜对的那样,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"));
}
在这里,每当 Func<T,bool>
return 的 true
代表 sample
时,我们就将 FirstOrDefault
存入 return sample
(这是使用 Arg.Is
的不同重载,它采用表达式,而不是传入参数的值)。
这通过了两个不同谓词的测试,因为 sample
满足了这两个谓词。它还通过了最后一个断言,因为它不会 return sample
用于检查不同 id 的函数。我们不能保证在这种情况下使用了特定的谓词,但它可能就足够了。否则,我们将在 Func 上使用参考质量。
希望这对您有所帮助。
我正在尝试使用 NSubstitute 来模拟来自 Substitute 的 return 值,但是我无法获得 return 正确值的替代值,因为方法签名正在使用 Func。
我已经看到这些问题,但无法将其与我的 Func 一起使用。
Mocking out expression with NSubstitute
我尝试模拟的界面是这样的(有点简单):
public interface IOrgTreeRepository<out T> where T : IHierarchicalUnit
{
T FirstOrDefault(Func<T, bool> predicate);
}
我用 NSubstitute 代替它,如下所示:
_orgTreeRepository = Substitute.For<IOrgTreeRepository<IOrganizationUnit>>();
然后我尝试像这样更改 return 值:
_orgTreeRepository.FirstOrDefault(Arg.Is<Func<IOrganizationUnit, bool>>(x => x.Id== _itemsToUpdate[0].Id)).Returns(existingItems[0]);
但它只是 return 一个代理对象,而不是我在 existingItems 中定义的对象。
然而,多亏了其他问题,我设法让它工作,但这对我没有帮助,因为我每次都需要一个特定的项目。
_orgTreeRepository.FirstOrDefault(Arg.Any<Func<IOrganizationUnit, bool>>()).Returns(existingItems[0]); // Semi-working
我猜它把 lambda 表达式当作一种绝对引用,因此跳过它?有什么办法可以模拟 return 值吗?
正如您猜对的那样,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"));
}
在这里,每当 Func<T,bool>
return 的 true
代表 sample
时,我们就将 FirstOrDefault
存入 return sample
(这是使用 Arg.Is
的不同重载,它采用表达式,而不是传入参数的值)。
这通过了两个不同谓词的测试,因为 sample
满足了这两个谓词。它还通过了最后一个断言,因为它不会 return sample
用于检查不同 id 的函数。我们不能保证在这种情况下使用了特定的谓词,但它可能就足够了。否则,我们将在 Func 上使用参考质量。
希望这对您有所帮助。