Green tests and ham
In which I attempt to make an nuanced point in the style of Dr Seuss
So you have code to be written and you know it is best
when you are writing that code to start with a test.
You’ve heard this from Charlie and Richard and Sue
and all kinds of people so you know it is true.
And also these people, these Charlies and Sues,
have all sorts of other things to say about tests too.
They’ve told your that tests should mainly be small
that the thing that you test should not be the program’s total and all.
(Well ok, do that a little.
DO test some things that are BIG
but aim on the whole for a great pyramid.
With lots of small things at the bottom
and some big ones on top
and things in the middle which both big and small they are not.)
And so you have done this, done like Charlie and Dick,
built a great pyramid on top of very small bricks.
But when it came time to refactor some years down the line
did all those tests that you wrote make sure that things worked out just fine?
Or did you hit problems?
Were things not all ok?
Did you find that your tests just got in the way?
So how did this happen?
What’s going on?
Could it be that Charlie and Sue were both totally wrong?
Like most things in life it’s not as simple as that
your head is for more than just holding your hat.
Things are all nuanced and complex and cruel
and you can’t get results following just one simple rule.
All of that mush between your ear and your ear
must be constantly thinking, “what’s going on here?”
Writing tests first is all well and good
(and if you’ve never tried it then really you should).
But much more important than when it was written
is what that test looks like and what it does when its bidden.
If you have tests with fingers in the guts of your code
those tests are tied to those guts and won’t want to let go!
When your code is gutted those tests will always pull back
(whether the change is elegant or some horrid hack).
So never write tests that put fingers in guts
(in short beware coupling it really does suck).
But coupling is subtle and not always easy to see
(and nasty and viscous it just won’t leave us be).
And when you can’t see it it’s hard to get rid
which brings us back to that great pyramid.
Now it’s true that the things at the bottom might well be small
but that’s not the reason that they’re down there at all.
With smallness comes a danger that’s hard to explain
but that danger and putting fingers in guts is the same.
Things from the classroom, those cool algorithms
those things are small and are usefully hidden
in all of the programs that we want to write
they’re tiny, and hidden and used out of sight.
Those things are general, and rarely will change
(though we might swap them for others where the interface is the same).
Small things like those are all nice and stable
not like the small things in our code we often test just cos we’re able.
Our small things are different, they’re just part of the guts
of our webapps and services and front ends and such.
Our small things will change as we change our designs
they’ll vanish, disappear come to the end of their times.
If our tests are mainly written in terms of those
they’ll constantly be changing and causing us woes.
If these are mainly the tests that we choose to write
then the behaviour we want from our app drops out of sight.
And when those tests are gone (along with the units they test)
then ones at the top will be the only ones left.
The ones at the top that are too slow to run
too flakey and awkward to help get anything done.
The base of that pyramid isn’t defined by size
it’s defined by the things for which those tests should strive.
Tests at the bottom they have to be fast and easy to run
(when we make a change running them is step number one)
Fast alone of course just isn’t enough,
the tests at the bottom must do other cool stuff.
Whenever we run them the result must be always the same
(if that isn’t the case there’s no end of pain).
So these tests are fast and they run anywhere
(so any coder can run them without hours of despair).
So why is it important that the things they test are small?
It isn’t important, just not important at all!
What is important is that the thing they test
is just one sensible thing picked out of all of the rest.
One thing with behaviour that isn’t too likely to change
a thing that must happen no matter how our code is arranged.
Of course things always change, we know that they do
so some of the bricks at the bottom will always have to change too.
Some will go missing, some might leave gaps.
All we are saying is that perhaps,
if we stop thinking of size when writing our tests
things are more likely to work out for the best.
Before I go I must mention the one thing that we lose
by forgetting about size in the units we choose.
When we test small things it’s easy, when something goes wrong
to point to the bit where the problem comes from.
With big things that’s harder as there’s more to look through
so there is an advantage to testing small things its true.
But on balance, often (if we must make a choice)
it is the test suite built on stable foundations that will make us rejoice.