resp78
resp78

Reputation: 1534

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

I had following code

public interface IFoo
{
    void Execute();
}

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

    public abstract void OnExecute();
}

and following test case to test the Execute() method

[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(); call would go to FooBar.Execute()

later I decided to make the interface into an abstract class

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

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

    public abstract void OnExecute();
}

Now sutMethod.Execute(); call does not invoke FooBar.Execute()

I thought FakeItEasy would handles interface and abstract classes as equal.What am I missing?

Update @ Blair Conrad provided the reasoning for the behaviour

Is it possible to make minimal changes to the test case to get the original behaviour back?

thanks

Upvotes: 2

Views: 582

Answers (2)

Blair Conrad
Blair Conrad

Reputation: 241790

The difference is due to the overrideability of the method Execute on FooBar. FakeItEasy can only override virtual members, abstract members, or interface members.

In your original example, when IFooBar is an interface and FooBar implements it, Execute is a concrete method. It's not virtual, nor is it abstract. Thus FakeItEasy can't intercept calls to it, and the original method is executed.

Once you change IFooBar to an abstract class, you have an abstract IFooBar.Execute, which you override in FooBar. As such, FooBar.Execute is now virtual and can be intercepted by FakeItEasy. Which it does, so your implementation is not called.

Upvotes: 3

resp78
resp78

Reputation: 1534

Following addition help solve the issue

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

This calls the virtual method Executeof FooBar

Upvotes: 1

Related Questions