Reputation: 1534
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
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
Reputation: 1534
Following addition help solve the issue
A.CallTo(() => sutMethod.Execute()).CallsBaseMethod();
This calls the virtual method Execute
of FooBar
Upvotes: 1