Magic Trick to Write Effective Tests

The One Trick to Writing Effective Tests

How do you know your test is effective? How do you know your test protects you from breaking changes? And how can you do TDD without doing TDD? The best distillment of TDD taken from a TDD workshop in JFokus.

We all know that tests are good, right? Reduce regressions, and increase confidence. If done right, they can be a live documentation for our code. Many developers do write tests, and that is a day-brightening thought for me.

I’m not one to delude myself. Even though the benefits of TDD are well understood, I know most people do not practice TDD. I’ve been wondering what’s missing in After-the-Fact tests that usually make developers claim that tests are “useless”, “time-consuming” and have small to no value at all.

When I visited JFokus, the first workshop I went to was a TDD workshop ran by Raniz. Besides being a brilliant workshop, one part caught me as it described something I’ve been trying to grasp for a long time: the essential part in writing a test!

This is what Raniz said:

Image
TDD for cheaters, by Raniz

What is the problem with so many tests that Raniz solves here?

The problem we are talking about is tests that do not really test.

Let me explain. When you write your code, and it works via manual test, you are happy. Then you write a test for this working code and expect it to work. Why, of course! The code is working!

What’s the problem with that? Let’s look at an example:

Test the expandmode API. The multi mode should allow both items to be expanded.

The test above looks logical.

  1. We arrange the API to be in the right state – element.expandMode = 'multi'.
  2. Act by changing the expanded state of the items to true.
  3. We would expect both items to be true.

But… (you expected a “But” here, right?)

This test will pass without any code. Why? Because we set the values of the items’ expanded to true and expect them to be true. Hence, this should work even if we have an empty class!

Needless to say, this test will pass even if we change the expandMode to single.

Can you see the problem? Our test doesn’t really test anything except that setting something to true sets it to true.

The One Trick to Write Effective Tests

What Raniz distilled in his talk is the importance of failing a test. For any TDD practitioner, this is as obvious as the sun rising in the east, the north star shining in the north, and that Sith lords come in twos.

pltn style, Master and apprentice sith lord, cute big circular reflective eyes, Pixar render, unreal engine cinematic smooth, intricate detail
We all know they come in twos, right? Master and apprentice?

In our example, simply changing the state in the first line of the test case from multi to single would let us know if we are expecting the right thing.

Now, for those of you who are not writing tests before implementation, this is great news!

TDD without TDD

I like the phrase TDD for Cheaters.

Why? Because it allows developers to write more meaningful tests in a kind-of TDD fashion.

Just follow the steps outlined in the TDD for cheaters “algorithm”. How to write TDD after the fact:

  1. Write the code
  2. Comment it out
  3. Write the test
  4. See that it fails for the right reason
  5. Make it pass
  6. Refactor
  7. Repeat (from step 3)

Summary

The one trick to make sure your tests are solid is to make sure the test fails with the wrong conditions or when you delete the code that’s supposed to make it pass.

This one simple trick will prevent cases in which your test doesn’t really protect. Moreover, the wrong test can mislead a developer trying to understand how the API works.

Looking for more testing tips on how to write better tests? You can look here.

Thanks a lot to Yishai Nachliel for the kind and thorough feedback.


Sign up to my newsletter to enjoy more content:

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments