Beginner's Guide for Unit Testing Errors
Terror from an error. Photo by Cristian Palmer on Unsplash

Beginner's Guide for Unit Testing Errors

Recently, while working with one of the people I coach on test automation (and unit testing specifically), I used the slang term “error bubbles up”.

A few moments later, I had to explain the meaning of the phrase and how layering/stacking of the code works. This knowledge could help others so sharing it with you! ??

The goal of the article is to provide you:

  • a simple visualisation of the code execution layers
  • a practical example of how to unit test errors

This post targets beginner developers or test automation engineers (SDETs) learning “how to unit test”. All examples are made in JavaScript with the Mocha test framework

1 - Stack the layers

Let’s start by talking about “how it all works” when you run the tests. If you are using JavaScript language you are likely to run your tests with the Node.js runtime.

Node.js will start the testing framework, like Mocha.

Mocha will execute the test code.

Test code will execute the code under test.

Code execution layers (aka "call stack"). Photo by Cristian Palmer on Unsplash

2 - Unstoppable error

What happens if the code under test throws an error? The error will start in the code and crash it… then it will go one layer up to the test code and… CRASH IT!

Then it MIGHT crash the test framework (might… largely depend on the framework). This is where the “bubble up” phrase comes from. It goes up, and up, and up…

Crash could mean that other tests would not be executed… You’d need to spend some time to investigate and fix it.

Not cool!

Error bubbles up. Photo by Cristian Palmer on Unsplash

3 - Practical example

Example time!

Let’s say you have a piece of functionality to reverse a string.

And you have a sample test to see if it works:

So far so good.

You are excited about the progress of development! You have a working piece of code and the test for it!

You decide to implement some validation functionality! Perhaps when you pass a parameter into this function it must be defined (aka ‘not falsy’)? If so, it is not a good value and the code must throw the error!

Note that this error is thrown DELIBERATELY. Sometimes in your code these errors might appear accidentally and you must be ready for these situations and know “how my code will behave if the error is thrown?”

You could try testing it like that:

When you try to run this test, we will see that it DID NOT PASS! ? It crashed because of the logic that threw an error!

Error: Haiia, string must be defined!
    at reverseString (file:///C:/ivanAndCode/repo/index.js:2:22)
    at Context.<anonymous> (file:///C:/ivanAndCode/repo/test/index.test.js:10:16)
    at process.processImmediate (node:internal/timers:478:21)
        
Note that the above crash output example is a textual representation of the picture that I shared in the beginning of this article. The top line being the error, then where in happened in the code, then where in the test, etc.

4 - Catch it!

What to do? You need to let your test code know that you are EXPECTING an error. You should stop it from going BEYOND THIS ONE TEST that you are currently running.

This can be achieved by using try…catch statement.

You are calling the reverseString() function with an empty string and expect that it will throw an error! And then you check that this error is exactly what you expect! Awesome, you are done! BIG SUCCESS! ??

You are done, right?

Right?

5 - Not quite done

Imagine that tomorrow you wake up and decide “I DO NOT NEED THIS EXTRA VALIDATION!”… so you remove the code doing it.

As a diligent developer, you run your tests again and THEY PASS! ?

Happy!? ??

Wait a second, did you not have a test that should’ve failed when this behaviour changed? You did, kind of… The problem was that this test DID NOT have a check to alert you when the code DOESN’T THROW when it SHOULD’VE THROW.

it('Should throw error when string is not defined', () => {
  const expectedError = new Error('Haiia, string must be defined!')

  try {
    reverseString("")
  } catch (error) {
    assert.deepEqual(error, expectedError)
  }
})
        

reverseString() call was a success. Because of the success, the catch block never happened. So the test is happily passing when it should be failing!

This is not a good and robust test!

Let’s fix it by adding the extra assertion!

The message in this assertion is for you to figure out what is wrong, but QUICKER. What you say here is not very important... Because under normal conditions it will not run. It is an extra helper for emergencies!

When you run the tests now, they will fail with this special message:

AssertionError [ERR_ASSERTION]: Expected values to be loosely deep-equal:

[AssertionError: "It should've thrown an error but didn't" == 'bad'] {
  actual: "It should've thrown an error but didn't",
  code: 'ERR_ASSERTION',
  expected: 'bad',
  generatedMessage: true,
  operator: '=='
}
        

This is what we expected?? You are finally happy with the test! (and decide to leave validation logic in the code)

Summary.

  • Errors are bubbling up in the call stack.
  • Catch them in your tests (and code)!
  • Test for the situations when the error is mistakingly not thrown

Catching error that has bubbled up. Photo by Cristian Palmer on Unsplash


The end

If you read till the end, you are the best! If you enjoyed it, don’t forget to react or leave a comment. This helps the algorithm to show it to other relevant people. More people see and react, which means I am more motivated to write more. I write more and YOU will benefit from reading it. ????


Are you a manual tester? Or a beginner automation engineer? Want to be better? Want to learn more about test automation and not sure how to go on this journey? I can help!

I coach people on test automation within the JavaScript ecosystem. UI/API/Unit/Performance/Contracts, you name it… You can book a free first consultation to talk about your needs and goals here: https://ivanandcode.com/coaching

Ivan invites you to click the link!


Hussain Ahmed

Passionate about Software testing, QA and technology.

6 个月

Love how you simplify complex concepts with relatable examples! ??

Ivan Karaman

Principal QA Engineer | Test Automation Coach | Quality Advocate

6 个月

See also my other articles: https://www.dhirubhai.net/in/ivanandcode/recent-activity/articles/ Want to learn test automation with me? Book a free session here: https://ivanandcode.com/coaching

回复

要查看或添加评论,请登录

社区洞察

其他会员也浏览了