Saturday, September 5, 2009

Fake scopes explained

FakeItEasy has a scoping feature that lets you configure calls only within a scope or asserting that calls was made within a specific scope.

A scope implements IDisposable and the Dispose method closes the scope, this means that to create a scope you create a using statement for it:

using (Fake.CreateScope())
{
    // Do something within the scope...
}

Any calls configured within a scope are only valid within that scope, this means that you can override the behavior of a faked method for just a small part of your test, for example:

public void Configuring_calls_in_scope()
{
    var factory = A.Fake<IWidgetFactory>();

    factory.Configure().CallsTo(x => x.Create()).Returns(A.Fake<IWidget>());

    using (Fake.CreateScope())
    {
        factory.Configure().CallsTo(x => x.Create()).Throws(new Exception());

        // This will throw since the method was configured in this scope.
        factory.Create();
    }

    // This will return a fake widget as configured before entering the scope.
    var widget = factory.Create();
}

Scopes also affects what calls are visible when getting the calls made to a fake object, when you’re inside a child scope and use the Fake.GetCalls(foo)-method or the RecordedCalls-property on a Fake<T>-object only the calls made within that scope are visible. In an outer scope the calls made in the outer scope and any child scope are visible:

public void Getting_calls_in_scope()
{
    var factory = A.Fake<IWidgetFactory>();

    factory.Configure().CallsTo(x => x.Create()).Returns(A.Fake<IWidget>());

    var widget = factory.Create();

    // This will succeed since there was a call to the create method
    // in the current scope.
    Fake.Assert(factory).WasCalled(x => x.Create());

    using (Fake.CreateScope())
    {
        // This will produce 0, no calls were made to the create method 
        // in the current scope.
        int numberOfCalls = Fake.GetCalls(factory).Matching(x => x.Create());

        // This will throw:
        Fake.Assert(factory).WasCalled(x => x.Create());
    }

    using (Fake.CreateScope())
    {
        factory.Create();
    }

    // This will now return 2 since there was one call in the outer scope
    // and another one in the inner scope.
    int numberOfCalls = Fake.GetCalls(factory).Matching(x => x.Create());
}

1 comment:

  1. At last! I found this truly amazing article. I am very happy that I found this very good article of yours. Very good info and very creative post. Thanks.

    John
    www.imarksweb.org

    ReplyDelete