Why you should make your tests fail
Cathal Mac Donnacha 🚀
Posted on December 2, 2021
Let's face it, most of us developers don't necessarily love writing tests. We sometimes end up rushing through them, and once we see that green tick next to a passing test, we're generally pretty happy to move on. However, an enemy is lurking amongst us.
False positive test
The enemy I'm talking about here is otherwise known as a false positive test. Let's take a look at what this beast looks like.
Here we have a select
element with some countries as options:
<select>
<option value="">Select a country</option>
<option value="US">United States</option>
<option value="IE">Ireland</option>
<option value="AT">Austria</option>
</select>
Here's my test:
it('should allow user to change country', () => {
render(<App />)
userEvent.selectOptions(
screen.getByRole('combobox'),
screen.getByRole('option', { name: 'Ireland' } ),
)
expect(screen.getByRole('option', { name: 'Ireland' })).toBeInTheDocument();
})
The test passes, isn't that great? ✅ I'm afraid not. ðŸ˜Â Let's see why after we intentionally make it fail.
Making your test fail
Here's a real example of a false positive test situation I ran into recently:
it('should allow user to change country', () => {
render(<App />)
userEvent.selectOptions(
screen.getByRole('combobox'),
screen.getByRole('option', { name: 'Ireland' } ),
)
// Changed expected country from "Ireland" to "Austria" - this should fail.
expect(screen.getByRole('option', { name: 'Austria' })).toBeInTheDocument();
})
I was expecting the check for "Austria" to fail because it wasn't the selected country, and I was pretty surprised to see that it was still passing. Looks like we have just identified a false positive test.
Let us take a step back. The purpose of my test is to ensure that when changing a country, it is indeed the now selected option. However, after debugging for while I eventually realised that the test above only checks that the country "Ireland" exists, instead of checking if it's selected.
Here's how I eventually fixed it:
it('should allow user to change country', () => {
render(<App />)
userEvent.selectOptions(
screen.getByRole('combobox'),
screen.getByRole('option', { name: 'Ireland' } ),
)
// Now checking if the option is selected
expect(screen.getByRole('option', { name: 'Ireland' }).selected).toBe(true);
})
Now, I am correctly checking that the option is selected and all is good. I wouldn't have found this unless I intentionally made my test fail, so I'm glad my persistence has paid off and I avoided a potential bug.
Final thoughts
I've been burnt enough times in the past by false positive tests that I have vouched to always intentionally make my tests fail before moving on to the next one. Since doing this, I've gotten a lot more confident in my tests knowing that they'll only pass in the correct circumstances.
That's about all I have to share with you today. Let me know in the comments if you found this article useful. 🙌
Want to follow along?
I mainly write about real tech topics I face in my everyday life as a Frontend Developer. If this appeals to you then feel free to follow me on Twitter: https://twitter.com/cmacdonnacha
Bye for now 👋
Posted on December 2, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.