When I write code that really matters, I prefer to design in the test-driven style:
- Figure out the next behavior that I need to implement
- Answer the question "What single test can I write that demonstrates I'm one step closer to implementing that behavior?"
- Write it and see that it fails (to show that I'm testing something sensible or that I've already finished that step)
- Implement that part of a feature
- Clean up the tests and the code
- Repeat until done
Not everyone on my team does this, and that's fine—it's more important that we deliver working, well-tested, robust features than that we all use the same style. Sometimes, however, the other developers check in features and ask me to help them write tests.
You can take this idea too far even as a rule of thumb, but I'm starting to believe that there's an inverse correlation between the difficulty of testing a feature and implementing a feature which corresponds to the quality of design.
In other words, when Allison said to me the other day "This code was really easy to write!" and I said "It was more difficult to test than to write (but it wasn't difficult to test)", that's a good sign that we've found great abstractions and discovered effective APIs in our code.
The difficulty of the tests is in building and selecting the right test data to expose all of the branches in the code.
You can obviously take this rule of thumb too far: some code is difficult to write and tedious to test because of low quality. Some code is easy to write and difficult to test because it does too much in a very obvious and straightforward way that merits some serious refactoring.
Still, when the balance of work in my programming goes toward crafting effective and useful and correct tests, I start to believe that I'm on the right track to crafting great code.
Maybe that's because you're writing integration tests instead of unit tests? In this post http://www.modernperlbooks.com/mt/2012/12/not-the-final-word-on-mock-objects.html you state mocking is useless, and in fact you're having integration tests without mocking.
Maybe. I find the distinction between integration and unit tests to be uninteresting. I prefer to think of tests in terms of the level of interaction they test, such as view tests or model tests. Because those levels build on each other, that lets me test the integration of that level and the levels on which it depends as well as the specific details of that level.
Distinction between unit and integration tests is exactly the point here.
With mocking you can test each particular "if" and "else" in your code easy - you don't need to build all layer stack and environment to write the test.
Also unit vs integration tests are different purpose, good example here
http://blog.stevensanderson.com/2009/08/24/writing-great-unit-tests-best-and-worst-practises/
Sure, but what does that gain me? That may tell me that there's a problem in one specific component, but it doesn't tell me if that component works with other components. I still have to test that, and if those tests fail (and if I've written them well), I can diagnose the component at fault.
Better yet, I don't have to create and maintain two or more instances of the same code (the mock and the real).