Test Driven Development is the best way to write quality software. If you're not in love with it, you suck. Don't argue, just learn harder and eventually you will get it.
Sounds familiar?
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0 ratings0% found this document useful (0 votes)
49 views
When TDD Fails: September 24, 2011
Test Driven Development is the best way to write quality software. If you're not in love with it, you suck. Don't argue, just learn harder and eventually you will get it.
Sounds familiar?
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 3
September 24, 2011
When TDD Fails
Test Driven Development is the best way to write quality software. If you're not in love with it, you suck. Don't argue, just learn harder and eventually you will get it. Sounds familiar? Unfortunately, it does to me. I've seen way too many people with this attitude, both online and offline. It's kind of ridiculous, considering TDD has obvious problems in certain areas of programming. I haven't seen many articles discussing these problems, so this is my attempt of mending the issue. Partly, it's inspired by a recent article on Peter Sergeant's blog. TDD works well when most complexity in your code comes from algorithms contained inside your methods or classes. Let's say, you are tasked to write a function that calculates the number of business days between two calendar dates. Ideal for TDD. Fairly generic code with straightforward, narrow interface and tricky logic inside. All you need for testing it are two dates and a holiday calendar. It is easy to come up with meaningful tests before you start implementing anything. Moreover, this is the kind of code that is likely to be reused and hence augmented with new functionality in the future. The more generic it is (dependency-inject the calendar!), the better. TDD is nearly useless when your code is the opposite of what I've described above: specific and mostly trivial, with complexity coming from the sheer amount of methods and their interactions. It's not that you can't test such code, it's that your tests will not provide any value. Typical MVC controller methods (actions) are a good example of this issue. Firstly, action methods often interface with multiple fairly complex systems, some of which you don't have under your control. Simply setting up a test requires you to add
numerous interfaces, wrappers, code for dependency
injection and so on. Now, many programmers would argue that it's good design, but it really isnt if you use all that added code just for tests and don't do anything with it in your actual application. In that case it's pure bloat of the same kind that plagues most enterprise software. Oh, and good luck mocking your database and HTTP request objects. Secondly, action methods are not reusable. They express specific logic applicable to a single scenario. You can, of course, assert that your method PrintHelloWorld outputs Hello world! before proceeding to write it. It might even help you catch a typo by the virtue of you typing the same thing twice. Problem is, that's about as useful as it gets. Whereas testing generic logic allows you to assert some fundamental properties of the system and the information it works with (which will be used all over the place and are unlikely to change), testing pieces of specific logic is an exercise in proof-reading. Not to say that such proof-reading is useless, it's just that the kinds of errors it catches are pretty rare and can be easily caught using much less labor-intensive methods. Now, consider its downside: huge amounts of added inertia. Business requirements changed? Rewrite your tests. Someone changed names of the views? Rewrite you tests. You want to use a different repository class? Rewrite your mock code, and then rewrite your tests. Thirdly, and most importantly, preemptive unit tests are not going to catch the bugs that arelikely to happen within and around your action methods. They are not going to tell you about a typo in the field name of an HTML form. Neither will they pinpoint a missing record in the database. In other words, they are not going to catch the bugs that arise on the boundaries of different subsystems in you app.
I was speaking about action methods, because they are a
good illustration, but, of course, there are lots and lots of similar types of code out there. Glue code. Simple methods that interface with several complex subsystems. That code is wrong. Anything that is not testable is bad design. Anything that is designed using test-first methodology is good design. Okay, maybe I'm going a bit overboard with fake quotes. Still, it is also a real, popular attitude I see among developers. They are equating a particular development process with quality, even though that process is used to ensure quality. It's a kind of circular argument. Sure, unit testable code is not going to be a horrendous spaghetti of giant methods that do twenty different things each, tweaking global state every step of the way. But there are plenty of other ways to develop crappy software. Create countless layers of abstraction. Make everything a framework, pushing all the real work (and bugs) into configuration files and the database. Split functionality into tiny pieces that make no sense on their own, but somehow work together. I've seen it done. Heck, going overboard with test-fist approach sometimes encourages these things. My point? I guess it's similar to the one made by Peter Sergeant. I'm not saying TDD is a bad thing, but there are more tests than unit tests, and there are more ways to verify software than testing. If you choose a methodology without comparing it against alternatives, if you claim that it works all the time without evaluating the results, than you're not doing engineering - you're practicing a religion.
(Ebook) Pragmatic unit testing in Java with JUnit by Andy Hunt, Dave Thomas ISBN 9780974514017, 0974514012 - The latest updated ebook version is ready for download