Don't be doing Test Driven Development

Test Driven Development is actually quite good. It forces you to think ahead when you are developing code and to ensure that you understand the requirements. If you can manage it, it's pretty awesome.

Many-to-One Job Relationships

However - there are two kinds of software development company, and that really comes down to how many developers do how many jobs. If you work for one of the big companies, then for every job in that company there will be more than one person doing that job - probably two people for the job, or maybe 1.24 people.

If you work for a small/medium company, a startup maybe - then typically each person does two or three jobs.

This isn't a judgement on either company - or a suggestion that the individuals are lazy or anything. A company like say Google can't afford to provide poor service just because someone is sick. This is a natural consequence of SLAs. But at the same time they can afford to have multiple individuals dedicated to one potential task. It's basic redundancy - that makes sense to everyone.

In the small/medium company, I know how to do my job and I also know how to do the jobs of three or more others, and vice versa - we spread it around.

So what has this got to do with TDD...

TDD in the SME is a luxury. Those companies can't look at spending a day or two for each task to build out tests that are quite speculative (or seem so at this point in time).

Yes, yes, yes - I know that's a false economy that's not really up for debate. 

Even with good code, changes that are introduced after initial development can introduce nasty bugs - and test code provides a necessary safety net to ensure regression is avoided when changes are worked on two or three months later. But if the company is not sure whether it will be in business next week, never mind in six months test writing is not going to be the highest priority.

What to do?

Pragmatic Test Driven Development

Two contradictory points:

  1. You gotta write tests. Come on - it's not negotiable.
  2. Tests are a pain to write
Ways around this...

First, write a test

If you want you can do this as TDD - but I wouldn't bother.

Make sure you write at least one test. Then you might just write another one.

So what's going to be in that test - well, the minimum amount possible.

Let's start with some code (right from a TDD perspective we've automatically failed - but I can live with that):

case class AccountTransaction(accountId: Long, value: Float, note: String)

This is Scala but don't let that phase - it's just a simple class with a general constructor - it's not that different from any other language.

How to test this...

Write the minimum you have to - start with a class (just as easy to do in JUnit or whatever).

class AccountTransactionTest extends AnyFunSuite {
}

This will probably cause a compiler error because you generally have to have at least one test - so let's shove one in:

class AccountTransactionTest extends AnyFunSuite {
    test("Can create an instance") {
    }
}

Seriously lazy. Probably enough - but the bare minimum is probably too minimum.

How about:

class AccountTransactionTest extends AnyFunSuite {
    test("Can create an instance") {
        val t = AccountTransaction(null, null, null)

        println(t)
    }
}

Now that's a thing of beauty.

Okay, let's list all the horrible things about that. For starters, using null in general is yuck - using null in Scala is a capital offence. Then all we are doing is a println - which will just print the object out as a collection of nulls. And we're not really testing anything.

So is it all bad. Well no - firstly, we have a test, and this is always better than having no test. Of course, we can waste time writing tests - for example, writing tests for simple getters and setters, especially generated ones - but for the most part having tests is good.

More importantly this is a basic boiler plate for a test. If you are working in a team, you have laid a markers to state clearly that tests are a thing. And the next developer who looks at this code might just copy and paste this and write a decent test.

There is also validation stage, even if it's not automatic. If someone runs this, especially the original author, then there's a fair chance they can verify that the output is correct.

Constructing an object with all nulls is of course a valid case - and probably one where you'll want to throw an exception or somehow guard against that... at which point you are going to have to change this test to catch the exception.

Assertions

Simple rule - never write println(x) (or whatever) in a test. This should always be an assertion.

Yeah - sod that. Swap the never/always:

Always write a println(x) - never write an assertion.

Obviously, you want to write lots of tests and you can't use println in automated testing - or not without writing some kind of assertion in a much more difficult place.

But to start, writing a println takes the pressure of figuring out that difficult bits of testing, i.e. how am I going to dig into the response of this code and assert that it contains the correct values - rather than focusing on how to call the code in the first place.

See that 'AccountTransaction' above - isn't it cute. It's the kind of class you see in books about code development and testing... it's not the kind of class you see in the wild, or at least when you do, it's not the one you really need to test.

So - pop in the println and when you see bits that you can test, then stick in an assertion. Solve the problem one puzzle at a time.

Concluding

I'm not trying to dis testing - quite the opposite. But a pragmatic approach to it, where tests actually get written and systems are more stable because regression is avoided, is going to lead to a better world for every.

Test Driven Development is just a little to academic to be practical - but hey, if it works for you, go for it.
















 

Comments