November 11, 2017
I was refactoring specs of some Rails application when I decided to mock the
ImageUploader class of CarierWave. I wanted to be able to check for specific image url. But was it a good idea?
I know it might be tempting to mock libraries that make database or network calls to make specs run faster, but that’s not what test doubles are meant for.
Test doubles are meant to help you create practical and convenient interfaces between parts of your application.
Imagine you have to create some thing that you should integrate in already existing code.
Using test double you can easily check if the interface of the thing (that is not implemented yet) is clear and easy to use. And if not – it’s cheap to throw it away and start over.
Now looking from this perspective you should see that mocking third-party thing doesn’t make any sense.
But not only it’s meaningless…
I mean, TDD is not only about testing, it’s also about design. Mocking external lib won’t help you to create good design, because you don’t have any control over it.
The idea is to use mocks as quick and rough prototypes, to see how your thing will be integrated into existing code. If you see that the interface is not very handy – you just write the mock differently, with different methods or with different method signatures.
So you just prototype your interface first and write your implementation later.
Now if you apply this logic to mocking external library (which interface you cannot change), you’ll see that it makes zero sense.
Got it? Let’s continue…
Most obvious danger is getting false positives (or negatives, depends on perspective). In other words your test will pass where the actual thing won’t work. Either because you’ve mocked it in a wrong way or the library you were mocking changed slightly after an upgrade.
Also by mocking an external lib you are binding yourself to a specific implementation and it will be much harder to change the library in the future.
Another downside is that you might end up with a lot of excessive code that doesn’t bring any value. It can also make it harder to understand what is going on in your code.
If that’s really a problem – create wrappers around that third party thing.
Don’t forget to write integration tests for that wrappers.
As a bonus you’ll make it clear what functions of that external lib you really use, and it will be much easier to replace that dependency later.
In my case I went with using
ImageUploader directly, writing a wrapper for it would be just crazy.
I hope this small article will help you avoid this caveat.
If you are interested in further reading on that topic – here are some more articles: