Don't Mock What You Don't Own
Originally posted on maksimivanov.com
I was refactoring the specs of some Rails application when I decided to mock the ImageUploader
class of CarrierWave. I wanted to be able to check for specific image URLs.
Was it a good idea?
No, Don’t Do It
I know it might be tempting to mock libraries that make up databases or network calls to make the 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 doubles, you can easily check if the interface of the thing (that is not implemented yet) is clear and easy to use — if not — it's cheap to throw it away and start over.
Now, looking from this perspective, you should see that mocking a third-party thing doesn't make any sense.
Not only is it meaningless…
Wait, What Perspective?
TDD is not only about testing, it's also about design. Mocking external lib won't help you create a 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.
Just prototype your interface first and write your implementation later.
Now, if you apply this logic to mocking external libraries (whose interfaces you cannot change), you'll see that it makes zero sense.
Got it? Let's continue…
It's Also Harmful
The most obvious danger is getting false positives (or negatives, depends on the perspective). In other words, your test will pass where the actual thing won't work, either because you've mocked it incorrectly 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. It will be much harder to change the library in the future.
Another downside is that you might end up with a lot of excess code that doesn't bring any value. It can also make it harder to understand what is going on in your code.
But HTTP And Database Calls Make My Tests Slow
If that's really a problem, create wrappers around that third party thing.
Don't forget to write integration tests for those 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.
Summary
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 reading further on this topic – here are some more articles:
- http://davesquared.net/2011/04/dont-mock-types-you-dont-own.html
- http://www.markhneedham.com/blog/2009/12/13/tdd-only-mock-types-you-own
- http://blog.8thlight.com/eric-smith/2011/10/27/thats-not-yours.html
- http://stackoverflow.com/questions/1906344/should-you-only-mock-types-you-own