开发者

When using a mocking framework and MSPEC where do you set your stubs

I am relatively new to using MSpec and as I write more and more tests it becomes obvious to reduce duplication you often have to use a base class for your setup as per Rob Conery's article

I am ha开发者_JS百科ppy with using the AssertWasCalled method to verify my expectations, but where do you set up a stub's return value, I find it useful to set the context in the base class injecting my dependencies but that (I think) means that I need to set my stubs up in the Because delegate which just feels wrong.

Is there a better approach I am missing?


The initialization/setup of stubs belongs to the arrange phase. The arrange phase is used to get the system into a known state before you exercise it.

In MSpec, the arrange phase is performed in Establish fields. For example:

public class When_the_temperature_threshold_is_reached
{
    static ITemperatureSensor Sensor;
    static Threshold Threshold;

    Establish context = () =>
        {
            Sensor = MockRepository.GenerateStub<ITemperatureSensor>();
            Sensor
                .Stub(x => x.GetTemperature())
                .Return(42);

            Threshold = new Threshold(Sensor);
        };

    Because of = () => Reached = Threshold.IsReached(40);

    It should_report_that_the_threshold_was_reached =
        () => Reached.ShouldBeTrue();
}

When you write more tests using that kind of ITemperatureSensor, you should extract a base class that does complicated or repeated setup.

public abstract class TemperatureSpecs
{
    protected static ITemperatureSensor CreateSensorAlwaysReporting(int temperature)
    {
        var sensor = MockRepository.GenerateStub<ITemperatureSensor>();
        sensor
            .Stub(x => x.GetTemperature())
            .Return(temperature);

        return sensor;
    }
}

public class When_the_temperature_threshold_is_reached : TemperatureSpecs
{
    // Everything else cut for brevity.
    Establish context = () =>
        {
            Sensor = CreateSensorAlwaysReporting(42);

            Threshold = new Threshold(Sensor);
        };
}

This gives you the advantage that you can influence the stub's return value from the context itself: You do this by keeping as much information as possible local to the context and provide a good name for the "setup" method in the base class.

There is no need to specifiy or expect anything stub-related in Because. When Because is run, your system should be in a state where it can be exercised without further preparation.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜