Making sure all IWorker implementers call CanHandle from Handle without a mocking framework

lego-568039_1280

You have an interface that allows you to treat all worker classes – classes that handle a specific type of work – as just one type: IWorker;

    interface IWorker
    {
        public Boolean CanHandle(IWork work);
        public void Handle(IWork work);
    }

You want your worker classes to be able to do their work without having to check their backs every step of the way.

BUT

You have no way of guaranteeing that the classes that are handing out work to workers call Handle only if CanHandle returns true.

This may be a bit of a contrived example, as in this case you’d probably be better off avoiding the problem altogether. But for the sake of argument let’s say that is not an option and that the calling `CanHandle` from `Handle` is just an example of you needing to make sure that the implementer of one method always calls another and and acts according to the returned value.

To make every worker call CanHandle itself and only proceed with the actual work if everything is ok, you could of course provide a base class that does this. Ensuring with tests that the base class sticks to the pattern of calling CanHandle from Handle would be easy to do. And it would allow specific workers to focus on their own specific processing.

Hang on though … having such a base class kinda defeats the object of having an interface: not tying yourself to a distinct class hierarchy.

So how can you ensure that every class that implements the IWorker interface has implemented its Handle method in a way that protects the actual processing code from being handed cows when it is designed to handle chickens? Working out that you ended up with a sliced and diced pair of jeans because some distributor blindly handed your Levi’s to a kitchen worker instead of a laundry worker, is not exactly fun or easy.

The way to protect yourself from late night debugging sessions has three parts:

  • You need a way to test every class implementing IWorker with the same set of tests.
  • You need a way to substitute the actual implementation of CanHandle with an implementation that does exactly what your tests need it to do.
  • You need two tests to verify that Handle calls CanHandle and proceeds in accordance with what CanHandle returns.

1. Executing the same tests for every class implementing IWorker

Ensuring that every implementer of IWorker is tested with the same set of tests, is pretty simple when you are using NUnit and not much more difficult when using MSTest (just a little more work).

When using NUnit this boils down to using a generic test class and using the TestFixture attribute to specify the classes to be tested.

    [TestFixture(typeof(KitchenWorker))]
    [TestFixture(typeof(BathroomWorker))]
    class IWorker_ContractTests<T> where T : IWorker, new()
    {
        IWorker MakeWorker()
        {
            return new T();
        }

        [Test]
        public void TestMethod1()
        {
            IWorker worker = MakeWorker();
            // ...snip...
        }
    }

For more information check out these two posts:

2. Substituting CanHandle

To verify that Handle acts according to what CanHandle returns, you need to be able to control what CanHandle returns. This means you need to substitute the actual implementation of CanHandle with whatever your tests needs it to do.

Using a mocking framework that is a piece of cake. But what if you can’t use a mocking framework?

Oops?!?

Yup. Without a mocking framework you are definitely in a bit of a pickle.

Unless…

When dealing with interfaces, you always have the option of wrapping the implementing class that you want to test in a “Test wrapper” and selectively delegate its methods to the “actual” implementer. Something like this.

    class TestWrapper : IWorker
    {
        IWorker _WorkerUnderTest;
        EnsureCanHandle _ReturnsThis;

        public TestWrapper(IWorker workerUnderTest, EnsureCanHandle returnsThis)
        {
            _WorkerUnderTest = workerUnderTest;
            _ReturnsThis = returnsThis;
        }

        public Boolean CanHandle(IWork work)
        {
            return (_ReturnsThis == EnsureCanHandle.ReturnsTrue);
        }

        public void Handle(IWork work)
        {
            _WorkerUnderTest.Handle(work);
        }
    }

    enum EnsureCanHandle
    {
        ReturnsFalse,
        ReturnsTrue
    }

The test wrapper in this example takes the actual worker to be tested as the first parameter of its constructor. The second parameter dictates the result that CanHandle will return. The test wrapper’s implementation of CanHandle does what is required by the test, while its implementation of Handle delegates to the actual worker.

3. Testing Handle

You want all classes implementing IWorker to call CanHandle from Handle. And you only want Handle to proceed with the actual work when CanHandle returns true. When CanHandle returns false, Handle should throw an IndecentProposalError.

To achieve this using our test wrapper, you need to tweak the MakeWorker helper method of the generic test class to take a parameter that will dictate the result CanHandle returns. And of course you need to pass the desired CanHandle result in each of your tests. After that, all that’s left to do is to write the actual tests.

Like so.

    [TestFixture(typeof(KitchenWorker))]
    [TestFixture(typeof(BathroomWorker))]
    class IWorker_ContractTests<T> where T : IWorker, new()
    {
        IWorker MakeWorker(EnsureCanHandle returnsThis)
        {

            return new TestWrapper(new T(), returnsThis);
        }

        [Test]
        public void Handle_CanHandle_Returns_False_Should_Throw_IndecentProposalError()
        {
            IWorker worker = MakeWorker(EnsureCanHandle.ReturnsFalse);
            IWork work = new Work_Fake();

            Assert.Throws<IndecentProposalError>(
                delegate
                {
                    worker.Handle(work);
                }
            );
        }

        [Test]
        public void Handle_CanHandle_Returns_True_Should_Not_Throw_Anything()
        {
            IWorker worker = MakeWorker(EnsureCanHandle.ReturnsTrue);
            IWork work = new Work_Fake();

            Assert.DoesNotThrow(
                delegate
                {
                    worker.Handle(work);
                }
            );
        }
    }

That’s it. That’s how you make sure all classes implementing IWorker call CanHandle from Handle and proceed appropriately when you can’t use a mocking framework. Enjoy!

What code had you wondering how to test it? I’d love hearing from you by email or in the comments below. I read everything and will try to help where and as best I can.



Leave a Reply

Your email address will not be published. Required fields are marked *

*

Show Buttons
Hide Buttons