You Shall Not Test Methods
When discussing unit tests it often happen that I hear that "unit testing is about testing methods". I do not agree, and because this is something which surfaces here and there so I think the idea deserves a comment.
Let me use good, old
BankAccount example. It might be that it has methods
withdrawal(), but why should I care about testing them? All I care about is whether the
BankAccount, as a whole, provides the desired functionality. And what is the functionality I expect? Well, it can be roughly described by a number of test cases.
Case 1 Opening balance = 0, trying to withdraw 500, withdrawal refused, balance is still 0.
Case 2 Opening balance = 499, trying to withdraw 500, withdrawal refused, balance is still 499.
Case 3 Opening balance = 501, trying to withdraw 500, success, balance is 1.
Case 4 Opening balance = x, trying to deposit y, success, balance = x + y;
Case 5 Opening balance = x, trying to deposit y and y > 100000 EURO, error, notified the police cause you are probably trying to launder money. ;)
and so on.
See? It is all about the responsibilities of the class, not about methods. Methods are only means by which this class can fulfill its contract.
To test one case we usually have to use more than one method. And that is fine, because we do not give a damn about methods! It is responsibilities that we are after.
Counter-example (well, almost)
Oh yeah, I hear you, I hear you. "My
StringUtils class, has this
toUppercase() method and I test this very method, right?"
Well, not really. What you really test is the functionality that the
StringUtils provides, and because this functionality is so trivial that it fits within one method, this makes you think that you test a method. But in reality you test a functionality.
But why, oh why? What wrong happens when you write tests for methods? I believe two bad things usually happen:
- missing test cases - it is hard to come up with test cases when looking at the already written method; some of the important ones will be forgotten
- testing of implementation - because you see implementation you test implementation which results in tests containing a lot of implementation details and poorly-focused tests (tests which tend to test many test cases at once and are very fragile because of this).
BTW. Isn't it exactly the difference between the test-first and test-last approaches?
- Do not test methods.
- Do not think about methods when testing.
- Do think in terms of class responsibilities. Period.
P.S. It is all about the mindset, you know.