Overall I agree with most of Justin’s points. However, I get the feeling that he, like many folks, approaches testing as a method for verifying the correctness of code. As I understand the thesis, CUPID is to testing what SOLID is to design.
While I’m not opposed to laying down some names and concepts to improve the state of testing, I don’t belive testing should be the goal. It’s not about testing. I believe testing is a tool to be used in guiding your design.
I realize that it’s unfair to pick on sample code used in talks, but “Problem 2: Stubbing instead of mocking” provides a great illustration. Here the author claims that we too often stub where we should be mocking. He gives the following snippet:
Firstly I had to get over the use of the old RSpec 1.0-style
#stub! and the
#and_return syntax. After resetting my brain I quickly
realized the test was awkward. I re-read it a few times and then asked, “why
stub, or mock for that matter, methods on the object under test?”
A design issue emerges
This is a design issue! The
BalanceCalculator is doing too much work. This is
the “S” in SOLID - the Single Responsibility Principle. The friction of this
test suggests that we need to adjust the design.
For example, we could wrap the account info and account type into a cohesive object to be passed into the calculator.
To stub or to mock?
Forgiving that design issue for now, let’s get back to the author’s point - should we mock or stub those methods?
The methods in question are queries. The
BalanceCalculator presumably uses
the results of those queries to do its work. So why do we need to set an
expectation that we should call those methods? Afterall, if we don’t call them
we’ll not have their resulting values, so we won’t be able to do the work, so
the test should fail. Right?
And if we don’t call those methods and the test passes, then they neither need to be mocked nor stubbed as they are unnecessary.
So, to stub or mock… how do we know when to use which?
My heuristic is that stubs are for queries and mocks are for commands. In a very generic sense I’m talking about Command-query separation applied to testing.
It’s all design
In the end nearly everything we do is design in some sense. Testing is no exception, and is in my opinion a much larger part of the design of software systems than it is given credit for. Or at least, I believe we should be striving to make it so.