Skip to content
Robert Coltheart edited this page May 7, 2019 · 3 revisions

What is Machine.Fakes ?

Machine.Fakes can best be described as an extended integration layer between Machine.Specifications and different mock/fake/substitute frameworks.

Machine.Fakes attempts to simplify the usage of such fake frameworks on top of MSpec by helping to reduce a lot of the typical mocking-related code in specifications.

Machine.Fakes helps you to stay mostly independent of a concrete fake framework by providing a little wrapper API and a provider model for fake frameworks.

Getting Started

Installation

Currently there are 5 packages available on NuGet. These are the core framework and the different adapters for Rhino.Mocks, Moq, NSubstitute and FakeItEasy. You can install one of the flavors below:

All necessary dependencies to MSpec and the mocking framework are taken care of for you.

How to use it

The core of Machine.Fakes consists of only two classes: WithFakes and WithSubject<TSubject>.

WithFakes

By deriving from WithFakes you can use the An<TFake>(), Some<TFake>() and The<TFake>() methods for creating fakes as well as the extension methods based API for setting up the behavior. The WithFakes class only provides the basic fake framework abstraction.

class When_using_a_car : WithFakes
{
    static Car subject;
    static bool stopped;

    Establish context = () =>
    {
        var engine = An<IEngine>();

        The<IEngine>()
            .WhenToldTo(x => x.TurnOff())
            .Return(true);

        subject = new Car(engine);
    };

    Because of = () =>
        stopped = subject.StopCar();

    It should_turn_off_engine = () =>
        stopped.ShouldBeTrue();
}

WhenToldTo is used for setting up a behavior but Machine.Fakes also supports behavior verification on fakes with the WasToldTo and WasNotToldTo extension methods.

class When_using_a_car : WithFakes
{
    static IEngine engine;

    Establish context = () => 
        engine = An<IEngine>();

    Because of = () =>
        engine.TurnOff();

    It should_turn_off_engine_once = () =>
        engine.WasToldTo(x => x.TurnOff());
}

Machine.Fakes even provides an abstraction for the various kinds of inline constraints used in the different fake framework flavors using the Param and Param<T> classes.

class When_using_a_car : WithFakes
{
    static Car car;
    static bool tires_serviced;

    Establish context = () =>
    {
        var engine = An<IEngine>();

        engine
            .WhenToldTo(x => x.Service(Param<string>.Matches(part => part == "Tires")))
            .Return(true);

        car = new Car(engine);
    };

    Because of = () =>
        tires_serviced = car.ServiceTires();

    It should_service_tires = () =>
        tires_serviced.ShouldBeTrue();
}

These constraints get translated to the inline constraints of the target framework when Machine.Fakes executes. Machine.Fakes even preserves the nice verification error messages from the target frameworks and still allows you to be independent of the mocking framework.

WithSubject<TSubject>

In our car example, we don't actually need to create the mocks by hand. We can make it even simpler by introducing the concept of auto-mocking to the specification. We take advantage of this by using WithSubject<TSubject>.

class When_using_a_car : WithSubject<Car>
{
    static bool stopped;

    Establish context = () =>
        The<IEngine>()
            .WhenToldTo(x => x.TurnOff())
            .Return(true);

    Because of = () =>
        stopped = Subject.StopCar();

    It should_turn_off_engine = () =>
        stopped.ShouldBeTrue();
}

The generic type parameter tells Machine.Fakes what to create for the specification. Each interface or abstract base class dependency in the constructor of the type will be filled automatically by the configured fake framework via dependency injection.

You can access the created instance through the Subject property. The actual subject is created on the first read access to this property. If you want to modify the subject when the context is established, go ahead, you can do so. You can even replace the subject by hand in case the automocking approach falls short:

class When_using_a_car : WithSubject<Car>
{
    Establish context = () =>
        Subject = new Car(The<IEngine>());
}

Now that we are automatically creating the subject, we can manipulate the injected dependencies by using the The<TFake>() method which lets us access the fakes.

For finer-grained control over the creation of the mocks, we can also configure individual interfaces:

class When_using_a_car : WithSubject<Car>
{
    Establish context = () =>
    {
        // Lazily create a custom mock
        Configure(x => x.For<IEngine>().Use(() => new DummyEngine()));

        // Use dependency injection
        Configure(x => x.For<IHeadLights>().Use<DummyHeadLights>());

        // Neater dependency injection
        Configure<ITires, DummyTires>();
    };
}

Behavior Configurations

Very often we try to accomplish re-use in classes by using inheritance and of course you can do so with Machine.Fakes. However in .NET you can only inherit once and inheritance may not be the weapon of choice for more cross cutting aspects like a global interface, for example ISystemClock.

Machine.Fakes offers a composition model for specifications called "behavior configurations".

public class BehaviorConfig
{
    OnEstablish context = fakeAccessor => {};
    OnCleanUp subject = subject => {};
}

BehaviorConfig mimics the setup and teardown phases of the context / specification. It offers access to all the fakes in a specification and can clean up the subject after a specification. You only have to implement the relevant delegate, as Machine.Fakes ignores uninitialized delegates. An example for a BehaviorConfig in the context of ISystemClock like this:

public class CurrentTime
{
    public CurrentTime(DateTime time)
    {
        Time = time;
    }

    public static DateTime Time { get; set; }

    OnEstablish context = fakeAccessor =>
    {
        fakeAccessor.The<ISystemClock>()
            .WhenToldTo(x => x.GetCurrentTime())
            .Return(Time);
    };
}

This is the car example with a behavior configuration instead of configuring the fake itself:

class When_using_a_car : WithSubject<Car>
{
    static string dash_display;

    Establish context = () => 
        With(new CurrentTime(new DateTime(2018, 2, 14)));

    Because of = () => 
        dash_display = Subject.GetDashDisplay();

    It should_display_the_current_date = () => 
        dash_display.ShouldEqual("It's Feb 14th, 2018");
}

Faking properties

Behaviours can be set up for fake properties like this:

The<InterfaceWithProperty>()
    .WhenToldTo(x => x.Property)
    .Return(propertyValue);

But property values are also automatically tracked. So you might as well just set the value that should be returned:

The<InterfaceWithProperty>().Property = propertyValue;

This way you can also check whether a setter has been called:

The<InterfaceWithProperty>().Property.ShouldEqual(propertyValue);

⚠️ The Rhino Mocks adapter is a bit special here: a fake will stop tracking its properties as soon as you set a behavior on one of them.

Faking out and ref parameters

The FakeItEasy and NSubstitute adapters support setting up values for out and ref parameters on faked method calls. For example, a method

public interface IReturnOutAndRef
{
    void Invoke(string input, out string output, ref object additional);
}

can be faked this way:

string output;
object additional;

The<IReturnOutAndRef>()
    .WhenToldTo(x => x.Invoke("a", out output, ref additional))
    .AssignOutAndRefParameters("b", new object());

output will be set to "b" and additional to a new object instance.

AssignOutAndRefParameters will use the given values to set up all out and ref parameters in the order they appear in the method signature. Any non out and ref parameters are ignored.