C# 如何使用NSubstitute替换Object.ToString?

C# 如何使用NSubstitute替换Object.ToString?,c#,nsubstitute,C#,Nsubstitute,当我尝试使用NSubstitute 1.7.1.0来定义的行为(这是一个虚拟方法)时,NSubstitute抛出了一个异常 复制: [Test] public static void ToString_CanBeSubstituted() { var o = Substitute.For<object>(); o.ToString().Returns("Hello world"); Assert.AreEqual("Hello world", o.ToStr

当我尝试使用NSubstitute 1.7.1.0来定义的行为(这是一个虚拟方法)时,NSubstitute抛出了一个异常

复制:

[Test]
public static void ToString_CanBeSubstituted()
{
    var o = Substitute.For<object>();
    o.ToString().Returns("Hello world");

    Assert.AreEqual("Hello world", o.ToString());
}
有没有办法通过上述测试


我的幼稚测试引发的异常是一个bug还是“出于设计”?

您将很难从
System.Object
中替换任何方法,因为.Net对它进行了非常特殊的处理

例如,由于相同的原因,这也会失败:

[Test]
public void x()
{
    var o = Substitute.For<anything>();
    o.GetHashCode().Returns(3);
    Assert.AreEqual(4, o.GetHashCode());
}
[测试]
公共空间x()
{
var o=替换为();
o、 GetHashCode()。返回(3);
AreEqual(4,o.GetHashCode());
}
但这很好:

public class Anything {
    public virtual string Else() {
        return "wrong";
    }
}

[Test]
public void x() {
    var o = Substitute.For<Anything>();
    o.Else().Returns("right");
    Assert.AreEqual("right", o.Else());
}
公共类任何东西{
公共虚拟字符串Else(){
返回“错误”;
}
}
[测试]
公共空间x(){
var o=替换为();
o、 Else()返回(“右”);
Assert.AreEqual(“right”,o.Else());
}
很抱歉,我无法提供更好的消息,但模拟低级对象在.Net中效果不太好。

NSubstitute基于库,使用动态代理拦截和管理调用。在这两个框架中都禁止截取对象类的方法

  • Castle的IProxyGenerationHook默认实现中禁止了它。你可以找到代码。我认为这是有原因的。当然,可以实现自己的IProxyGenerationHook,允许对象类的方法拦截,但是

  • NSubstitute还抑制对对象方法的拦截,原因是NSubstitute的语法。“NSSubstitute记录对替换进行的调用,当我们调用返回时,它将捕获最后一次调用并尝试将其配置为返回特定值。”假设我们有以下代码:

    var service = Substitute.For<IService>();
    var substitute = Substitute.For<object>();
    service.AMethod(substitute).Returns(1);
    
    var service=Substitute.For();
    var substitute=substitute.For();
    服务。方法(替代)。退货(1);
    
    我们在这里调用“AMethod()”,NSub截取执行并生成其内部内容,假设将“substitute”值添加到一个调用substitute.GetHashCode()的字典中。如果我们截获“GetHashCode()”方法,那么它将是最后一次录制的调用。NSub会将指定的返回值绑定到它,这是错误的。这几乎是不可能避免的


  • 谢谢你的回答,感谢你在回答中付出的努力。然而,这种行为似乎更像是NSubstitute的疏忽,而不是.NET中的“魔法”(如果涉及“魔法”,我想了解更多;-)。不幸的是,这不是疏忽。“System.Object”对象不是普通的.Net类。它是垃圾收集器的根,是IL中分配的标识符,是非托管COM对象。它深深地埋藏在.Net运行时中。我是这个项目的贡献者之一,我可以说,一旦你深入到IL的深处,事情并不总是像C#中那样。祝您的NSU替换工作顺利!
    var service = Substitute.For<IService>();
    var substitute = Substitute.For<object>();
    service.AMethod(substitute).Returns(1);