The Most Important Skill When Writing Unit Tests Is Making Sure They Fail
Tags: programming, webdev, testing
Published: 2022-06-02 19:58:52


Yes, seriously…

Around one year ago, I came across [this LinkedIn post by Craig Livings](https://www.linkedin.com/posts/craiglivings_tdd-agile-activity-6706831864751120385-yAdN) who posted this controversial statement:
>  Any test that has never failed adds no value #tdd #agile

![Mind blown 🤯](https://cdn-images-1.medium.com/max/2000/1*eWwfY-afALfPoFC5K7EqWQ.gif)

What it means is any test that has never failed has no value, and therefore, can be deleted. In order for any test to add value, it must have failed at least once.

Let’s see why failing our tests is such an important skill…

## Why must our tests fail?

Let us say we have written some code and some supporting unit tests. We’ve done good right? The tests have never failed, but we now have unit tests that support our code! Or at least we *think* we have…

Let’s look at some examples. One of a test that has not failed and one that has.

### The test that has never failed

This example is a common scenario where we are just focused on writing a test that passes. We have no intention to make it fail.

We will use the following JavaScript function:

```javascript
function sum(a, b) {
  return a + b;
}

module.exports = sum;
```

We have written the following [Jest](https://jestjs.io/) test to verify our sum function adds two numbers together:

```javascript
const sum = require('./sum');

test('two plus two is four', () => {
  expect(2 + 2).toBe(4);
});
```

We run the test and it passes ✅

That’s it. We’re happy the test has passed so we move on.

### The test that has failed

In this example, we use exactly the same code. However, this time we make sure the test fails to prove its value.

Using the same function:

```javascript
function sum(a, b) {
  return a + b;
}

module.exports = sum;
```

And using the same test:

```javascript
const sum = require('./sum');

test('two plus two is four', () => {
  expect(2 + 2).toBe(4);
});
```

We run the test and it passes ✅

But this time we want to make sure the test has failed. So we decide to modify the code:

```javascript
function sum(a, b) {
  return 0;
}

module.exports = sum;
```

We re-run the test and we get another pass ✅

But wait… this should have failed. We removed the code that adds the numbers together.

We can see the reason the test still passed is that the test itself is incorrect. The test was not calling sum.

So we update the test:

```javascript
const sum = require('./sum');

test('two plus two is four', () => {
  expect(sum(2, 2)).toBe(4);
});
```

We re-run the test and it fails ❌

Ok, great! Now let’s put our code back:

```javascript
function sum(a, b) {
  return a + b;
}

module.exports = sum;
```

And we re-run the test and it passes ✅

Excellent, now our test has value because we have ensured the test is validating the correct thing.

The example is a simple one. However, when testing more complex code, it is difficult to spot these mistakes. This is why it’s so important we make sure our tests fail before we make them pass — so we have confidence in what we are validating.

## The takeaway

When writing tests, we must know they have failed, so we know they add value.

Do you agree?