使用ForPartsOf的NSubstitute虚拟getter返回替换会抛出异常

Thy*_*ine 5 c# mocking nsubstitute

我试图模拟一个对象的一个​​属性

有一个类似的问题: 返回返回另一个替代的方法的结果会在NSubstitute中引发异常 但是接受的答案对我不起作用.

void Main()
{
    var obj = Substitute.ForPartsOf<MyObject>();
    //WORKS, But I need a partial mock!:
    //var obj = Substitute.For<MyObject>();

    obj.PropClass.Returns(Substitute.For<PropClass>());

    //It's suggestion, Fails, same error:
    //var returnValue = Substitute.For<PropClass>();
    //obj.PropClass.Returns(returnValue);

    //Fails, same error:
    //Lazy implementation of *similar question*
    //Func<PropClass> hello = () => Substitute.For<PropClass>();
    //obj.PropClass.Returns(x => hello());

    //Fails, same error:
    //I believe what *similar question* suggests
    //obj.PropClass.Returns(x => BuildSub());

    obj.PropClass.Dump("Value");
}

public class MyObject
{
    public MyObject()
    {
        _propClasses = new List<PropClass>();
    }
    private readonly IList<PropClass> _propClasses;
    public virtual IEnumerable<PropClass> PropClasses { get { return _propClasses; } }
    public virtual PropClass PropClass { get { return PropClasses.FirstOrDefault(); } }
}
public class PropClass
{
}

public PropClass BuildSub()
{
    return Substitute.For<PropClass>();
}
Run Code Online (Sandbox Code Playgroud)

这些失败,但有例外:

CouldNotSetReturnDueToTypeMismatchException:
Can not return value of type PropClassProxy_9 for MyObject.get_PropClasses (expected type IEnumerable`1).

Make sure you called Returns() after calling your substitute (for example: mySub.SomeMethod().Returns(value)),
and that you are not configuring other substitutes within Returns() (for example, avoid this: mySub.SomeMethod().Returns(ConfigOtherSub())).

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.

Correct use:
  mySub.SomeMethod().Returns(returnValue);

Potentially problematic use:
  mySub.SomeMethod().Returns(ConfigOtherSub());
Instead try:
  var returnValue = ConfigOtherSub();
  mySub.SomeMethod().Returns(returnValue);
Run Code Online (Sandbox Code Playgroud)

Dav*_*pak 8

好的,这有点棘手.首先,解决方案是停止obj.PropClass调用基本实现:

obj.When(x => { var get = x.PropClass; }).DoNotCallBase();
obj.PropClass.Returns(prop);
Run Code Online (Sandbox Code Playgroud)

现在解释.NSubstitute记录对替换的调用Returns,当我们调用时,它会抓取最后一次调用并尝试配置它以返回特定值.

obj.PropClass.Returns(prop)跑步时发生的事情是真实obj.PropClass被召唤,而真实被召唤obj.PropClasses,所以NSubstitute现在认为obj.PropClasses是最后一次召唤.在Returns随后试图返回单PropClassPropClasses预计的IEnumerable<PropClass>,因此例外.

上面的修复程序会obj.PropClass立即停止调用基本实现,因此最后一次调用不会被替换为该调用,PropClasses并且Returns可以按预期工作.

不可否认,这是非常可怕的,也是我们长期将部分嘲讽纳入NSubstitute的原因之一.NSub的漂亮语法是以它无法始终能够区分开发人员何时需要运行实际代码来配置呼叫为代价的.对困惑感到抱歉.