Simple Dependency Injection and MiniTest::Mock

— Paul Annesley, March 2012

I recently wrote a Ruby client for Amazon Alexa’s APIs, and thought I’d
pull out an example of nice, simple dependency injection to facilitate unit
testing. Nothing revolutionary or complicated, just good practice.

The example is based around a UriSigner class, normally used by the calling
code like this:*credentials).sign_uri(uri)

The calling code doesn’t know or care that UriSigner depends on Base64,
OpenSSL::Digest::SHA256 and OpenSSL::HMAC. The unit test for
UriSigner, however, cares for two reasons.

Firstly, they’re external dependencies, and only need to be tested for correct
usage, not correct implementation.

Secondly, these dependencies represent an encoder and a cryptographic hash
function; they’re deterministic, but they return very opaque data which can
make tests and their failure messages difficult to understand.

So instead of testing against magical (computed in advance) Base64 strings and
HMAC hashes, I’ve used simple attr_writer dependency injectors:

The unit test can then inject MiniTest::Mock instances in place of the
real Base64 and HMAC implementations, setting expected method calls and their
return values:

As simple as that.

The same approach is used by the HTTP Client class to stub out actual HTTP
calls via Net::HTTP. There’s great libraries like VCR, WebMock and
FakeWeb for handling this, but sometimes it’s easier to keep it lo-fi:

This kind of dependency injection is one of many basic techniques which aren’t
fancy enough to get a lot of press, but go a long way to keeping your objects
and tests in order.

Got any thoughts? Hit me up, I’m @pda on Twitter,
where I generally write about this kind of thing.

← index