When I was first learning about testing I thought changing your code to make it easier to test was stupid. Since you are only supposed to test the public interface of a class, it seemed like cheating to fake out anything internal to a class. Over time, though, I realized that testing in this way lead to a bunch of unnecessary setup (usually creating a bunch of objects in the database) that I didn’t need. Take this typical (if extremely simple) use case class:
It’s pretty straight-forward — it just publishes an article if the article meets the article publishing policy. How should we test this? Previously, I would look up what the ArticlePublishingPolicy
class did and see something like this:
To use this class I need to have an article that is valid, plus the article needs an author who is in good standing (and what does that mean?). I could create an author, who is in good standing (that would mean looking at the class of the author to see how to make that the case), plus I’d need to make sure I put all the correct information into an article to make it valid for publishing, like marking it approved by and editor. This seems like a lot of work that is totally unrelated to the PublishArticle
class.
What if I changed the PublishArticle
class to this?
That let’s me write tests like this (in rspec, and assuming Article
responds to published?
):
All of the sudden these tests don’t test anything that the PublishArticle
class doesn’t care about. It doesn’t need to know about what makes an article valid, so we don’t test that here. Testing in this way makes tests faster, clearer, and less likely to change. Now, if something about the ArticlePublishingPolicy
has to change, there is no reason to change the code in PublishArticle
or your tests for it. Plus, you don’t need to change how you call PublishArticle
in your production code to use this technique since we’ve provided sensible defaults.
I hope this encourages people new to testing to change their code just for test purposes. Inject those dependencies!