尝试在 .Equals 上设置 return 时出现 CouldNotSetReturnDueToNoLastCallException

CouldNotSetReturnDueToNoLastCallException when attempting to set a return on .Equals

我正在使用最新版本的 NSubstitute,但出现以下错误:

NSubstitute.Exceptions.CouldNotSetReturnDueToNoLastCallException was unhandled
HResult=-2146233088   
Message=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);

这是一个复制错误的最小项目:

using System;
using NSubstitute;

public interface A
{
    string GetText();
}

public class Program
{
    public static void Main(string[] args)
    {
        var aMock = Substitute.For<A, IEquatable<string>>();

        aMock.Equals("foo").Returns(true);
    }
}

我怀疑这是因为 NSubstitute 无法模拟已经有实现的方法,即使这些是被模拟的接口,object.Equals 的默认实现也可能造成困难.

是否有其他方法可以在 NSubstitute 中为 .Equals 设置 return 值?

您是正确的,是 Object.Equals 导致了问题。有more info in this answer.

要变通,您可以强制它使用 IEquatable<T>.Equals,如下所示:

var aMock = Substitute.For<A, IEquatable<string>>();
var a = (IEquatable<string>)aMock;
a.Equals("foo").Returns(true);

这要求被测试的代码也使用该方法而不是 Object

这种困难导致我尽量避免使用 NSubstitute 模拟 EqualsGetHashCodeToString。一种丑陋但有效的方法是使用您自己的 equals 实现 IsEqualTo(A a),它在实际代码中委托给底层 Object.Equals,但提供了一个简单的模拟位置。