Dependency Injection, Currying and Partial Application for easy Unit Tests

Curtis Tate Wilkinson
2 min readFeb 10, 2017

--

Optimally, when you’re following a functional paradigm, everything would be broken up into functions small enough that this doesn’t become an issue, but there are some occasions where you end up in a bit of a predicament with regards to testing. For example, you have a function interacting with a 3rd party system.

Say we have this function:

When it comes to testing saveAndProcessReturn(), there is going to be the annoying problem that this is going to go off and hit the API as though it was working in production. Sometimes this isn’t a bad thing (integration test), but in a lot of scenarios this isn’t something desirable.

This is a simple example which is easily changed to avoid this problem — the obvious pattern is to isolate this side-effecting code into their own functions, and inject the return into a formatting function. But for examples where this is much more difficult, I enjoy the following pattern:

Here is what happened:

  1. The API dependency was added as the first argument to the function
  2. An underscore was prefixed to the function name (to signify a partial function)
  3. A new function is created, which curries the Partial Function
  4. The imported API module is provided as the first argument to the new function

I’ve used Ramda’s “Curry” here, because it’s nicer than writing it as a curried function yourself, and I always write everything using Ramda anyway because it’s wonderful (Check it ramdajs.com).

The consequence of this is an incredibly testable function, because now, you can test it like this:

You can stub and have total control over the API module being injected into the function, so you can just replicate its behaviour using sinon.stub().returns() or the various other methods Sinon has (Check Sinon out if you haven’t already, so cool: sinonjs.org).

The only things that fall outside of the coverage of this are:

  1. The API module itself (external and should be tested with end-to-end integration tests) inside of your project
  2. Ramda’s curry method
  3. The small syntax of curry + partially applying arguments

This isn’t always the ideal solution and it can be avoided with a solid refactor most of the time, but it’s a nice and quick pattern to get things done, and get them tested.

--

--