Test driven (test) development
Do you have custom code in your acceptance test suite? A foundation that wraps around your test logic in a common, re-usable way?
For your own sanity, I hope the answer is yes.
Do you test that test suite foundation beyond the general use of your product (suite)? Do you have unit tests?
The answer is probably no.
do as we say…
We want developers to use TDD. It leads to better, more consistent, higher quality software. It makes refactoring easier. It gives testers more confidence in the product.
But what about our code? Couldn’t our code bases benefit from being better, more consistent, higher quality software? Wouldn’t easier refactoring ease a lot of burdens on test engineers?
Why aren’t we holding ourselves to the same standards that we hold our developers to?
perception as a product
We’re not actually hypocrites. Not intentionally, at least. The fact of the matter is, most members of our organizations won’t look at our test suites and see a product.
That includes many of the test engineers working on those suites.
But it is a product. It has end users and a real business impact.
I suggest we start changing this perception by changing the way we treat our test suites. Treat them like products. And what should developers be doing for any product?
I believe in TDD. And I believe it’s for everyone who writes code, including test code. So I used TDD when I wrote my most recent suite, and it saved me.
I was writing this test suite for a RESTful API. I needed to POST, GET, PUT, etc. Using Ruby, I chose a REST gem I was familiar with and built a foundation for my suite around it. I quickly had 100+ tests up and running.
That’s when I discovered a new requirement for my suite. To effectively test a certain subset of calls, I needed to make two different calls on one persistent HTTP connection.
I had never done that before, so I jumped into the REST gem’s source code looking for a way to do it. To my horror, I found that the gem didn’t support persistent HTTP connections.
don’t be lazy
My initial reaction to this crossroads was driven by pure laziness. I thought I’d use a new gem for persistent connection testing and the current setup for everything else.
This was a terrible idea. There was absolutely no reason to introduce another dependency into the suite, and furthermore, I would have had to write and maintain a second foundation for a subset of the tests.
I am ashamed, but I quickly came to my senses.
unit testing ftw
Like I said, I used TDD to develop the foundation for my test suite. let me refactor that abstraction layer with minimal effort.
I found a new gem that supported persistent HTTP connections and swapped it in for the old gem. My unit tests (predictably) failed.
But those failures pointed me to problematic areas. And I made changes. And tests turned green. All in all, it took me about an hour to make the switch.
When I ran the suite against our API, it was like nothing changed at all.
I’d call that a win for TD(T)D.
like an onion
Abstraction layers played a large part in the success of my transition from one gem to another. I’ll end up dedicating an entire post to the concept, but I didn’t want to downplay its effect.
I only had to touch three files in that anecdote. And two of them were unit test files. That was huge.
wrap it up
If you’re writing code, you should be writing unit tests. And when it comes to test suites, running the suite against a project build is not good enough!
Long live TD(T)D.