简体   繁体   English

如何使用NSubstitute替换Object.ToString?

[英]How to substitute Object.ToString using NSubstitute?

When I try to use NSubstitute 1.7.1.0 to define behaviour of Object.ToString (which is a virtual method), NSubstitute is throwing an exception. 当我尝试使用NSubstitute 1.7.1.0定义的行为Object.ToString (这是一个虚拟方法),NSubstitute被抛出异常。

To reproduce: 重现:

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

    Assert.AreEqual("Hello world", o.ToString());
}

The failure: 失败:

NSubstitute.Exceptions.CouldNotSetReturnDueToNoLastCallException : Could not find a call to return from.

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

Is there a way to make the above test pass? 有没有办法让上面的测试通过?

Is the exception thrown from my naive test a bug or is it "By Design"? 从我的天真测试中抛出异常是一个错误还是“按设计”?

NSubstitute is based on Castle.Core library and uses dynamic proxies to intercept and manage calls. NSubstitute基于Castle.Core库并使用动态代理来拦截和管理调用。 Interception of the Object class' methods is suppressed in both frameworks. 在两个框架中都禁止拦截Object类的方法。

  1. It's suppressed in Castle's IProxyGenerationHook default implementation. 它在Castle的IProxyGenerationHook默认实现中被抑制。 You can find the code here . 你可以在这里找到代码。 I think there are reasons for that. 我认为有理由这样做。 Sure, it's possible to implement own IProxyGenerationHook that allows Object class' methods interception, but... 当然,可以实现自己的IProxyGenerationHook,它允许Object类的方法拦截,但......

  2. NSubstitute also suppresses interceptions of Object's methods and NSubstitute's syntax is the reason. NSubstitute也抑制了对象方法的拦截,并且NSubstitute的语法就是原因。 "NSubstitute records the calls made on a substitute, and when we call Returns, it grabs the last call made and tries to configure that to return a specific value." “NSubstitute记录对替换的调用,当我们调用返回时,它会抓取最后一次调用并尝试配置它以返回特定值。” Assume we have the following code: 假设我们有以下代码:

     var service = Substitute.For<IService>(); var substitute = Substitute.For<object>(); service.AMethod(substitute).Returns(1); 

    We call "AMethod()" here, NSub intercepts the execution and makes its internal things, suppose adds "substitute" value to a dictionary which calls substitute.GetHashCode(). 我们在这里调用“AMethod()”,NSub拦截执行并生成其内部事物,假设将“替换”值添加到调用substitute.GetHashCode()的字典中。 If we would intercept the "GetHashCode()" method then it would be the last recorded call made. 如果我们拦截“GetHashCode()”方法,那么它将是最后记录的调用。 NSub would tie the specified return value to it which is wrong. NSub会将指定的返回值绑定到错误的位置。 It's nearly impossible to avoid such thing. 几乎不可能避免这样的事情。

You're going to have trouble substituting any methods from System.Object as it's treated very specially by .Net. 你将很难从System.Object替换任何方法,因为.Net特别处理它。

For example, this also fails for the same reason: 例如,由于同样的原因,这也失败了:

[Test]
public void x()
{
    var o = Substitute.For<anything>();
    o.GetHashCode().Returns(3);
    Assert.AreEqual(4, o.GetHashCode());
}

But this works fine: 但这很好用:

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

Sorry I can't give better news, but mocking low level objects doesn't work very well in .Net. 对不起,我无法提供更好的消息,但嘲笑低级别对象在.Net中效果不佳。

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

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