I keep hearing how developers say it’s kind of hard to get their minds around this testing thing, so I was then thinking to myself: "how did I get into this, by the way?"
It was at DevTeach 2003 when I first heard about unit testing. Scott Bellware was presenting a session about it. I decided to sit in and see what that was all about. Scott showed NUnit, and how to write some unit tests (sorry, that’s as much I can remember so many years later…).
Right after seeing that session, I decided to start writing some tests for some new code I was writing. At the time, I was writing the test after I wrote the production code, still trying to figure that NUnit thing. I was pretty pleased by having automated tests for some of my code.
Late in 2005, the same Scott came to Houston to present a full-day TDD workshop. Again, that was kind of long ago, and my memory is fuzzy. I remember Scott touched on dependencies, mock objects, how Test-Driven Development (TDD) helps keeping track whether the implementation is going on or off track, etc. I guess that was when I’ve heard of using TDD more as a design methodology than as a testing methodology, but I’m sure I didn’t quite *get* the idea back then.
Around that same time, I was working on a project here where we’ve decided we wanted developers to write more tests. We were using NUnit, and writing "integration" tests, not "unit" tests (as I came to realize later). We were writing tests to make sure the data put into our business entities were being saved and retrieved correctly to and from the database.
Right before starting off a new project (early in 2006), I looked back and noticed that a lot of redundant code was being written for those tests (instantiate entity, stick test values to its properties, save it, reload it, check to make sure the values saved are the ones expected, delete it, and have assertions all around to make sure things were working).
Decided to make that easier, I wrote a testing framework that’d do all that boring and repetitive work for the developers. For each business entity, the developer would create a test fixture class, make it inherit from a baseclass from my framework, override a method to provide test data to be pushed onto the entity, and give the baseclass the type of entity under test. The framework would then take care of doing all the heavy lifting and report any problems to the developer by means of assertions with as much detailed information possible (which property has failed, in which process, why, what could be causing it, etc.).
We had also noticed how much of a pain it was to create some specific test data that a given entity needed in order for it to be properly tested. I’ve then added some helper methods to my test framework that allowed the developer to pretty much ask for "5 entities of type Customer for tests", or something like that, and the framework would take care of creating those, giving it back to the developer (who could also tweak with the test entities, of course), and then cleaning it up afterwards.
The framework worked well, and the great thing about it was that it was pretty easy to get some good code coverage with those tests. However, at the time I *thought* we were doing unit tests, but we were actually doing integration tests. It finally downed on me that we should also be able to test things in isolation. That is, if what we need to test is a business rule, we shouldn’t need a live connection to the database, or even a data access layer for that matter. "A-ha, so that’s what those mock objects are all about, then", I thought to myself.
With that in mind, I decided to improve our testing framework so to make it easier for our developers to write unit tests for our business rules, so that they didn’t have to worry about the dependencies we have in our middle-tier framework in order to do so. After I’ve done some research on mock frameworks, I’ve decided to go with TypeMock, which I wrap up in my own special framework for testing our middle-tier components.
I’m currently working on rewriting some pieces of our testing framework in order to make use of some of the new features in C# 3.0 (such as object and collection initializers, lambda expressions, extension methods, etc.). This allowed me to clean up my API’s a lot (or so I think).
Everything I’ve mentioned so far has definitely improved my skills with doing TDD as a "testing" methodology, trying to make sure our code has some tests around it. That is something that most developers have a better time understanding and trying to do it, so that’s certainly valid.
Doing TDD as a "design" methodology is something eventually I got the idea and decided to start practicing it. This is definitely much harder for developers to get used to, because it really requires a different approach to writing software; different from what they’ve been doing for so many years now. However, like it’s been said over and over again by other people, when you really stick with TDD, then you start feeling bad about any code you write that you didn’t design beforehand, test-first.
By no means am I saying that I have mastered TDD (far from that), but I’m just certain that the code I wrote test-first is of much higher quality. Not only I believe my design is more solid (both because of the thought I’ve put through the design, but also because of the side-effect of getting the implementation under test), but I find it’s much easier to explain something to another developer by showing her the tests first, and then digging into the implementation.
I have been reading a lot of books, articles, websites, blog posts, other people’s code, etc., trying to improve my approach to TDD (which always entertains me by getting blown away by some code other people write). This has been great, and I plan to continue doing so.
I’ll probably have some more posts coming this way on the subject, as I get my mind around this thing. 🙂