gpt4 book ai didi

c# - 返回返回另一个替代方法的结果会在 NSubstitute 中抛出异常

转载 作者:可可西里 更新时间:2023-11-01 08:37:45 27 4
gpt4 key购买 nike

我在使用 NSubstitute 时遇到了一个奇怪的问题几次,虽然我知道如何解决它,但我一直无法解释它。

我精心设计了似乎是证明问题所需的最低要求的测试,它似乎与使用方法创建替代返回值有关。

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;
}

当我运行上述测试时,出现以下异常:

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.

但是,如果我更改测试方法以返回此内容:

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

或者这个:

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

有效。

我只是想知道是否有人可以解释为什么会这样?

最佳答案

为了使 NSubstitute 语法正常工作,幕后发生了一些困惑。这是它咬我们的那些案例之一。让我们先看一下示例的修改版本:

sub.MyProperty.Returns(someValue);

首先,调用sub.MyProperty,它返回一个IMyObject。然后调用 Returns 扩展方法,它需要以某种方式计算出它需要为哪个调用返回 someValue。为此,NSubstitute 会在某处的某个全局状态中记录它收到的最后一次调用。伪代码中的 Returns 看起来像这样:

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
}

所以评估整个调用看起来有点像这样:

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

现在让我们看看当我们在尝试设置返回值时调用另一个替代时会发生什么:

sub.MyProperty.Returns(MyMethod());

再次计算 sub.MyProperty,然后需要计算 Returns。在此之前,它需要评估 Returns 的参数,这意味着运行 MyMethod()。这个评估看起来更像这样:

//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!*

这可能导致的问题还有另一个例子 here .

您可以通过推迟对 MyMethod() 的调用来解决此问题,方法是:

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

这是有效的,因为 MyMethod() 只会在需要使用返回值时执行,所以静态 GetLastSubstituteCalled 方法不会混淆。

虽然我不这样做,但我更喜欢在忙于配置一个替代品时避免其他调用。

希望这对您有所帮助。 :)

关于c# - 返回返回另一个替代方法的结果会在 NSubstitute 中抛出异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16643526/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com