One bit of info that I’ve seen floating around on the ‘Net revolves around the idea that if you’re doing test-driven development you should start from the bottom up, writing tests for small pieces of functionality and then moving up through the layers. This sounds good, and I’m sure it works for some people, but I’m coming to the conclusion that it’s not right for me.
I was re-reading some of the older posts on Ted’s blog, and came across an article he linked to titled Test Driving Code: Top-Down or Bottom-Up? which made me think a little bit. My executive summary of the article is as follows…
- Top-down testing makes you focus on the specification of the business requirements of the code. The implementation becomes less of a distraction. Once your test is finished and passing, it becomes easy to refactor without tripping over your implementation.
- Bottom-up testing locks down your implementation to a certain degree. If you need to change your model for some reason, you also need to change your tests.
To give some background, my current project writes almost no unit tests. We write functional tests on DTO’s that are passed into and returned from a Facade layer. Our goal is to have each DTO map exactly to the system it’s targeting, which is most often the Presentation layer. Therefore, we’re effectively testing the very thin, logic-free (we hope) portion of the app that’s closest to the user. We don’t care how the DTO gets it’s data, just that the data that is there is correct. The end benefit is that we can easily refactor the domain model without tripping on our tests. The downside is that when a test fails, it doesn’t tell us where it’s failing, just that the client’s specification of what they want to see isn’t being met. Which means we spend a lot more time in the debugger than we otherwise might. It’s a tradeoff.
From my understanding, we largely got to this point through first-hand experience, as detailed by Ted in some of his posts:
I don’t have enough experience with writing actual unit tests to have a valid opinion on this matter, although I do know that I tend to think in a top-down manner, which fits in well with the way we write our functional tests. Now is that way of thinking natural to me, or a side-effect of coming to a project that already worked that way? I suspect I won’t know for a while.