Alan says you don’t have to use mocks for testing. “No, no, no!” he says. “If you never tested any collaborations with live objects, your rapid feedback test suite had limited use.”
That’s true; you don’t have to use mocks for testing – but try doing test / behaviour-driven design without them. It’s my fault; instead of writing “unit test or design” I should have put “unit test (read: design)”.
This is why I dislike the word test, though. As soon as the word test appears, everyone has a natural gravitation towards testing code after it’s been coded. Even though Alan is a very intelligent and imaginative developer who I know knows better than this, he still thinks instinctively of testing as being something which merely ensures that nothing’s broken. After all, you can’t test code before it’s been coded, can you?
Well, you can certainly write the test. The code will naturally follow – but this is why you have to mock out all the tools; because you haven’t got around to coding them yet. The functional or integration tests take care of the class interactions.
If you’re using JBehave’s StoryRunner to drive the functionality, then the functional tests (read: higher-level designs) all start out with mocks too!
It seems like this really at the heart of the “interaction vs. state-based unit testing” argument: http://www.martinfowler.com/articles/mocksArentStubs.html
A couple of points:
– Isolation is good, but you don’t have to isolate using mocks, you can use stubs
– Why go to the labor of mocking (or stubbing) system objects that are easy to create in your unit tests? You can stub out the ones that are hard to create, but what is the real value of stubbing out every single object and testing each piece of code in total isolation? It seems like overkill. Why not try to just remove test dependencies on objects that are difficult to create and on external systems such as databases, messaging systems, files, etc?
– If you use real system objects, you get more coverage because you are unintentionally touching parts of the code that may not be tested if you mock out all interacting object (this can be very beneficial when you start unit testing an existing codebase that has absolutely no unit tests, a.k.a. legacy code)