Using dependencies as a test oracle

I have long been a disciple of what is sometimes known as the “London school” of TDD (or “outside in” design), but I like to think I’m open to alternatives, when proven useful.

With that in mind, I found James Shore’s testing without mocks series very interesting. While I’m not quite ready to dive in at the deep end of that approach, one of the reasons to mock your dependencies (other than avoiding IO) is to remove the complexity from your tests, and James offers a handy alternative.

beforeEach(function() {
    dep1 = sinon.stub().resolves();
    ...
    handler = new Handler(dep1, dep2, dep3);
});

Rather than using [insert favourite mocking library] to represent those dependencies, and risking the slippage that can occur when the real version changes, but the tests are not updated (if you haven’t got contract tests for everything); you can use the real object (ideally, some pure “business” function) both in the set up, and also in your assertions, as a “test oracle“.

beforeEach(function() {
    dep1 = new Dep1();
    ...
});

it("should return the expected flurble", function() {
    ...
    const res = await handler.handle(req);

    expect(res.flurble).to.equal(dep1.bar(req.foo));
});

This way, if the implementation of the dependency changes, the test should still pass; unless it would actually affect the SUT.

I’m sure this approach comes with its own tradeoffs, and won’t help you with anything other than simple dependencies, but it can be useful in situations where you would like to use the real dependency and still keep the tests relatively simple.

(This is probably another force pushing in the direction of a ports and adapters architecture (or impure-pure sandwich), allowing you to use “sociable” tests in the kernel, and narrow integration tests at the edges.)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s