简体   繁体   English

用NSubstitute模拟Func的结果

[英]Mock result from Func with NSubstitute

I'm trying to use NSubstitute to mock the return value from a Substitute, but I cannot get the substitute to return the correct value because the method signature is using a Func. 我正在尝试使用NSubstitute模拟Substitute的返回值,但是由于方法签名使用的是Func,因此我无法获得替代方法来返回正确的值。

I've seen these questions, but cannot make it work with my Func. 我已经看过这些问题,但是无法使其与Func一起使用。

Mocking Action<T> with NSubstitute 用NSubstitute模拟Action <T>

Mocking out expression with NSubstitute 用NSubstitute模拟表达

The interface I try to mock is this (somewhat simplyfied): 我尝试模拟的接口是这样的(有点简单):

public interface IOrgTreeRepository<out T> where T : IHierarchicalUnit
{
    T FirstOrDefault(Func<T, bool> predicate);
}

I'm substituting it with NSubstitute like so: 我用NSubstitute替代它,如下所示:

_orgTreeRepository = Substitute.For<IOrgTreeRepository<IOrganizationUnit>>();

And then I try to change the return value like so: 然后尝试更改返回值,如下所示:

_orgTreeRepository.FirstOrDefault(Arg.Is<Func<IOrganizationUnit, bool>>(x => x.Id== _itemsToUpdate[0].Id)).Returns(existingItems[0]);

But it simply returns a proxy-object instead of my defined object in existingItems . 但是它只是返回一个proxy-object而不是我在existingItems中定义的对象。

However, thanks to the other questions I managed to get this to work, but it does not help me, since I need a specific item every time. 但是,由于其他问题,我设法使它起作用,但这对我没有帮助,因为我每次都需要特定的物品。

_orgTreeRepository.FirstOrDefault(Arg.Any<Func<IOrganizationUnit, bool>>()).Returns(existingItems[0]); // Semi-working

I guess it's treating the lambda expression as a kind of absolute reference and therefore skips it? 我猜它将lambda表达式视为一种绝对引用,因此跳过了它? Is there any way I can mock the return value? 有什么方法可以模拟返回值?

As you correctly guessed, NSubstitute just uses reference equality here, so unless you have a reference to the same predicate (which is sometimes an option) then you'll have to match any call ( Arg.Any or .ReturnsForAnyArgs ) or use an approximate form of matching to check the function passed in. 正如您正确猜测的那样,NSubstitute仅在此处使用引用相等,因此,除非您有对相同谓词的引用(有时是一个选择),否则您必须匹配任何调用( Arg.Any.ReturnsForAnyArgs )或使用近似值匹配形式以检查传入的函数。

An example of approximate matching: 近似匹配的示例:

[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"));
}

Here we've stubbed FirstOrDefault to return sample whenever the Func<T,bool> returns true for sample (this is using a different overload of Arg.Is which takes an expression, rather than the value of the argument passed in). 这里我们存根FirstOrDefault返回sample每当Func<T,bool>返回true对于sample (这是使用的不同过载Arg.Is它接受一个表达式,而不是传入的参数的值)。

This passes the test for two different predicates, because sample satisfies both of them. 这通过了两个不同谓词的测试,因为sample满足了这两个条件。 It also passes the last assertion, in that it doesn't return sample for a func that checks for a different id. 它还通过了最后一个断言,因为它不返回用于检查其他ID的func的sample We can't guarantee a specific predicate was used in this case, but it might be enough. 我们不能保证在这种情况下使用了特定的谓词,但这可能就足够了。 Otherwise we're stuck with reference quality on the Func. 否则,我们就无法保证Func的参考质量。

Hope this helps. 希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM