There were a few back-and-forth’s over testing and TDD over the last few days that I just caught up on – The Pragmatics of TDD, Test Trivial Code, and Don’t Unit Test Trivial Code. I consider myself pro-testing but against TDD as a diehard practice, so I thought I’d jot down a few thoughts on the subject.
(image from TDD, do you speak?)
First off, I’m not against Test Driven Development. I’ve always thought of it as a great way to get started with unit testing in your codebase, especially if you haven’t done any of it before. Using TDD you’re forced to think about “how do I make this code testable”, and a lot of other things like separation of concerns, SOLID principles, and other good software development pratices.
Not how I work
But that’s it – it’s a great way to get started. I don’t know about other people, but the way I think about code isn’t test-first. I prototype, I experiment, I tweak or add a new setting and see if it works. THEN I write tests. Again, it might just be a side effect of how I think, but I find the whole “You’re only allowed to think about this one thing until it’s completely done” aspect of TDD too limiting when it comes to software development.
Writing software is compliated. There’s tonnes of moving parts before you even get to your code – hardware, OS, drivers, language, libraries, etc. You have to take all that into consideration, imagine how all the pieces fit together, think of all the components you’re affecting while you write that one line of code. To force yourself into a “one line at a time” frame of mind seems unnatural for me, and I think a part of why some people have problems when starting TDD.
TDD isn’t a bad thing, but I’ve always seen it as training wheels. It forces you to answer questions like “how do I make this testable” or “am I putting too much functionality in this class?”, stuff you may not normally think about. But once those questions are always in the forefront of your mind, then you don’t really need TDD anymore. You can return to the larger picture of your project without being forced to think of each miniscule component, one at a time.
Tests are still important, and you should still have them. Our team has a strong culture of testing, and we usually require other members to write a few tests (at least) for each pull request they submit. Each bug fix should be accompanied by a fixed or new unit and/or integration test. But you don’t have to write them first – they just need to be there.
Oh yeah, the articles!
As far as those three articles go – I have to side with the “don’t test every little thing” part of the argument. Testing a pass-through or object mapping (without translations) method doesn’t really get you much other than asserting that your language knows how to assign values to properties or call methods. I’m pretty sure someone’s already tested that.