If You Can't Test It, You Need to Rethink It

You know that feeling of writing some code, having the best intentions to test it, then not actually knowing what to test? So you just let it go and think “I’ll deal with this later”, and forget about the tests? Your untestable code is actually an indicator of poor code quality.

In my last email I asked you to pick a piece of code and describe three things about it: Its responsibility, its abstraction, and its behavior. There are three things you need to have a solid grasp on before you can test something.

  • Responsibility is the reason the code exists. It should be clear and unambiguous.
  • Abstraction arises from responsibility. The abstraction is the mental model of what the object represents, and the concrete API for interacting with it.
  • Behavior is the specification that arises from Responsibility and Abstraction. If you do X, you expect to see Y in response.

Your tests only check behavior (that’s intentional, and we’ll talk about why later). But that means that if you don’t have a solid foundation of Abstraction and Responsibility to define the behavior, it’s difficult to know what to test.

If you don’t know the abstraction or responsibility of a module, then you don’t know where to put individual behaviors when developing a feature. If you can’t test it, it means you (or the person who wrote the code you inherited) probably haven’t thought through the responsibility and the abstraction, so the behavior is ambiguous and difficult to test. Getting clear on the responsibilities and resulting abstractions of your modules will make it much easier to determine what your test suite should contain.

Here’s an 8-minute video of me doing this Responsibility/Abstraction/Behavior exercise for a bit of code.

Next Up:
You Don't Need Strict TDD

Previously:
The #1 Thing Your Bootcamp Didn't Teach You


Want to impress your boss?

Useful articles delivered to your inbox. Learn to to think about software development like a professional.

Icon