Making a Duck-Dog using FakeItEasy's CallsBaseMethod(s)

A while back, Roman Turovskyy wrote FakeItEasy: Be Careful When Wrapping an Existing Object, an interesting post highlighting some of the difficulties of faking classes (as opposed to interfaces, which by virtue of having no behaviour of their own, are quite a bit more predictable). It's well-written and I enjoyed it, but he overlooked a small point. I figured others may easily make the same omission, so I'd like to explain why the example from that post works as it does, and to provide an alternative solution.


Mr. Turovskyy supposes we want to fake out the following Dog class:

public class Dog
{
    public virtual string Bark()
    {
        return "Bark!";
    }
    public virtual string BarkBark()
    {
        return Bark() + Bark();
    }
}

He notes that the default behaviour of a fake Dog, as made by dog = A.Fake<Dog>(), is for both Bark and BarkBark to return the empty string, which is not always desirable.

His next step is to create a fake by wrapping a Dog object:

Dog realDog = newDog();
Dog dog = A.Fake<Dog>(x => x.Wrapping(realDog));

Now Bark and BarkBark return the original (expected) strings.

Then Mr. Turovskyy addresses customizing the fake object to change the way it barks.

Here, things break down a little bit. His desired goal, of using A.CallTo to override Bark to return "Quack!" works, but when BarkBark is called, it still returns "Bark!Bark!".

He comments

For those who know how virtual methods work, this looks very counter-intuitive.

And that's completely true. The problem is that when a fake wraps an object, we're using a composition model, not inheritance. Thus the fake Dog knows to call the real dog's BarkBark method, but the real dog doesn't know about the fake Dog at all, so it just calls its own Bark method, which returns "Bark!".

Using the Wrapping option and then overriding Bark on the fake is equivalent to writing this manual wrapper:

public class WrappingDog: Dog
{
    private readonly Dog realDog;

    public WrappingDog(Dog realDog)
    {
        this.realDog = realDog;
    }

    public override string Bark()
    {
        return "Quack!";
    }

    public override string BarkBark()
    {
        return this.realDog.BarkBark();
    }
}

Mr. Turovskyy suggests getting the desired behaviour by writing a manual FakeDog that overrides Bark, which will work, but is tedious and discards the benefits that FakeItEasy can provide.

Another Way to Access Original Behaviour

FakeItEasy can be used to get the desired behaviour. It provides a CallsBaseMethod method when configuring a fake. It does just what you'd hope it would. Witness:

Dog dog = A.Fake<Dog>();
A.CallTo(() => dog.BarkBark()).CallsBaseMethod();

This tells the fake Dog to call the real Dog.BarkBark when its BarkBark method is invoked. When this is combined with an override for Bark, we can write this passing test:

[Test]
public void BarkBark_CallsBaseMethod_UsesOverriddenBark()
{
    Dog dog = A.Fake<Dog>();

    A.CallTo(() => dog.BarkBark()).CallsBaseMethod();
    A.CallTo(() => dog.Bark()).Returns("Quack!");

    string result = dog.BarkBark();

    Assert.That(result, Is.EqualTo("Quack!Quack!"));
}

Call Base Methods More Conveniently

As of FakeItEasy 1.24.0, there's an additional way to do this, and it may appeal more to users who want many methods on their fake to call the original class's version. There's a new fake creation option called CallsBaseMethods. It was proposed by Aleksander Heintz, who also provided nearly the complete implementation. When used, it will cause every method on a fake to delegate to the faked type's implementation, if there is one. So the previous test could be written as

[Test]
public void BarkBark_CallsBaseMethod_UsesOverriddenBark()
{
    Dog dog = A.Fake<Dog>(options => options.CallsBaseMethods());

    A.CallTo(() => dog.Bark()).Returns("Quack!");

    string result = dog.BarkBark();

    Assert.That(result, Is.EqualTo("Quack!Quack!"));
}

The change in the first line means that when dog is created, every method will delegate to the version on Dog.

Then Bark is overridden, and the base BarkBark is able to use the new version.

Now we can realize our dream of having a Seussian DuckDog: