返回返回另一个替代方法的结果抛出NSubstitute异常 [英] Returning the result of a method that returns another substitute throws an exception in NSubstitute

查看:488
本文介绍了返回返回另一个替代方法的结果抛出NSubstitute异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个奇怪的问题,而使用NSubstitute了几次,虽然我知道如何解决它,我从来没有能够解释它。

I have run into a weird issue while using NSubstitute a few times and although I know how to work around it I've never been able to explain it.

我已制定这似乎是最低要求的测试证明了问题,它似乎是与使用方法创建一个取代返回值。

I've crafted what appears to be the minimum required test to prove the problem and it appears to be something to do with using a method to create a substituted return value.

public interface IMyObject
{
    int Value { get; }
}

public interface IMyInterface
{
    IMyObject MyProperty { get; }
}

[TestMethod]
public void NSubstitute_ReturnsFromMethod_Test()
{
    var sub = Substitute.For<IMyInterface>();

    sub.MyProperty.Returns(MyMethod());
}

private IMyObject MyMethod()
{
    var ob = Substitute.For<IMyObject>();
    ob.Value.Returns(1);
    return ob;
}

当我运行上面的测试中,我得到了以下异常:

When I run the above test I get the following exception:

Test method globalroam.Model.NEM.Test.ViewModel.DelayedAction_Test.NSubstitute_ReturnsFromMethod_Test threw exception: 
NSubstitute.Exceptions.CouldNotSetReturnException: Could not find a call to return from.
Make sure you called Returns() after calling your substitute (for example: mySub.SomeMethod().Returns(value)).
If you substituted for a class rather than an interface, check that the call to your substitute was on a virtual/abstract member.
Return values cannot be configured for non-virtual/non-abstract members.



但是,如果我更改测试方法返回的:

However, if I change the test method to return this:

sub.MyProperty.Returns((a) => MyMethod());

或这样的:

var result = MyMethod();
sub.MyProperty.Returns(result);



它的工作原理。

It works.

我只是想知道如果任何人都可以解释为什么出现这种情况?

I'm just wondering if anyone can explain why this happens?

推荐答案

要获得NSubstitute语法的工作有一些混乱回事背后场景。这是它咬我们的案件之一。让我们来看看你的例子的修改版本第一:

To get the NSubstitute syntax to work there is some messiness going on behind the scenes. This is one of those cases where it bites us. Let's look at a modified version of your example first:

sub.MyProperty.Returns(someValue);



首先, sub.MyProperty 被调用,它返回一个 IMyObject 。在返回扩展方法,然后调用,它需要以某种方式工作,这称呼它需要返回 someValue中的。要做到这一点,NSubstitute其记录在一些全球性的状态下接收的地方最后一次通话。 返回伪上下的代码看起来是这样的:

First, sub.MyProperty is called, which returns an IMyObject. The Returns extension method is then called, which needs to somehow work out which call it needs to return someValue for. To do this, NSubstitute records the last call it received in some global state somewhere. Returns in pseudo-ish-code looks something like this:

public static void Returns<T>(this T t, T valueToReturn) {
  var lastSubstitute = bigGlobOfStaticState.GetLastSubstituteCalled();
  lastSubstitute.SetReturnValueForLastCall(valueToReturn);
  bigGlobOfStaticState.ClearLastCall(); // have handled last call now, clear static state
}



所以评估整个呼叫看起来有点像这样:

So evaluating the entire call looks a bit like this:

sub.MyProperty         // <-- last call is sub.MyProperty
   .Returns(someValue) // <-- make sub.MyProperty return someValue and
                       //     clear last call, as we have already set
                       //     a result for it

现在让我们来看看,当我们调用其他的替代品,而试图设定的返回值会发生什么:

Now let's see what happens when we call another substitute while trying to set the return value:

sub.MyProperty.Returns(MyMethod());



这再次评估 sub.MyProperty ,然后需要评估返回。才可以做到这一点,需要评估的参数返回,这意味着要运行的MyMethod()。这种评价更像是这样的:

Again this evaluates sub.MyProperty, then needs to evaluate Returns. Before it can do that, it needs to evaluate the arguments to Returns, which means running MyMethod(). This evaluation looks more like this:

//Evaluated as:
sub.MyProperty     // <- last call is to sub.MyProperty, as before
   .Returns(
     // Now evaluate arguments to Returns:
     MyMethod()
       var ob = Substitute.For<IMyObject>()
       ob.Value      // <- last call is now to ob.Value, not sub.MyProperty!
         .Returns(1) // <- ok, ob.Value now returns 1, and we have used up the last call
     //Now finish evaluating origin Returns:
     GetLastSubstituteCalled *ugh, can't find one, crash!*

有是存在的问题的另一个例子这可能会导致这里

There is another example of the problems this can cause here.

您可以通过电话来推迟的MyMethod解决此(),使用:

You can work around this by deferring the call to MyMethod(), by using:

sub.MyProperty.Returns(x => MyMethod());

这工作,因为的MyMethod()只会当执行它需要使用一个返回值,所以静态 GetLastSubstituteCalled 方法不会混淆。

This works because MyMethod() will only execute when it needs to use a return value, so the static GetLastSubstituteCalled method doesn't get confused.

相反不是做,虽然,我宁愿避免其他呼叫替代品,而我很忙配置之一。

Rather than doing that though, I prefer avoiding other calls to substitutes while I am busy configuring one.

希望这有助于。 :)

这篇关于返回返回另一个替代方法的结果抛出NSubstitute异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆