使用 fakeiteasy 的伪造行为(接口与抽象 class)的不一致行为

Inconsistent behaviour on a fake(interface vs abstract class) using fakeiteasy

我有以下代码

public interface IFoo
{
    void Execute();
}

public abstract class FooBar: IFoo
{
    public void Execute()
    {
         OnExecute();
    }  

    public abstract void OnExecute();
}

和下面的测试用例来测试Execute()方法

[Fact]
public void When_execute_method_called_Expect_executionTime_is_set()
{
    var sutMethod = A.Fake<FooBar>();

    A.CallTo(sutMethod).
                Where(x => x.Method.Name == "OnExecute").
                Invokes(x => Thread.Sleep(100)));

    sutMethod.Execute();

    Assert.NotEqual(0, sutMethod.Result.ExecutionTime.Ticks);
}

sutMethod.Execute(); 调用会转到 FooBar.Execute()

后来我决定把界面做成一个抽象class

public abstract class IFoo
{
    public abstract void Execute();
}

public abstract class FooBar:IFoo
{
    public override void Execute()
    {
         OnExecute();
    }  

    public abstract void OnExecute();
}

现在 sutMethod.Execute(); 调用不会调用 FooBar.Execute()

我认为 FakeItEasy 会处理接口和抽象 classes,因为 equal.What 我错过了吗?

更新 @ Blair Conrad 提供了行为的原因

是否可以对测试用例进行最小的更改以恢复原始行为?

谢谢

不同之处在于方法 ExecuteFooBar 上的可重写性。 FakeItEasy can only override virtual members, abstract members, or interface members.

在您的原始示例中,当 IFooBar 是接口并且 FooBar 实现它时,Execute 是具体方法。它不是虚拟的,也不是抽象的。因此 FakeItEasy 无法拦截对其的调用,并执行原始方法。

IFooBar 更改为摘要 class 后,您将在 FooBaroverride 获得摘要 IFooBar.Execute。因此,FooBar.Execute 现在是虚拟的,可以被 FakeItEasy 拦截。它确实如此,因此不会调用您的实现。

以下补充有助于解决问题

A.CallTo(() => sutMethod.Execute()).CallsBaseMethod();

这调用了FooBar

的虚方法Execute