DEV Community

Mariam Reba Alexander
Mariam Reba Alexander

Posted on

Unit testing: #1 - Test one behaviour at a time.

In the previous part of the blog series on unit testing, I mentioned the why part and summarised some points to be taken care of while writing unit tests. I am going to elaborate on these points one by one. To explain I will be using examples using Jest, a JavaScript testing framework.

Test a single behaviour

Tests are written in blocks and each block should ideally test for a single behaviour. Let us look at an example.

function sum(a, b) {
  return a + b;
}
module.exports = sum;
Enter fullscreen mode Exit fullscreen mode
const sum =  require("../src/sum");

test("should give sum of two numbers", () => {
  expect(sum("1", "2")).toBe(3); //assertion 1
  expect(sum(1,2)).toBe(3); //assertion 2
});
Enter fullscreen mode Exit fullscreen mode

There are 2 assertions above, one is testing the sum of two numbers of type string and the second is testing the sum of two numbers of type number.

1 Test failed

The above test block fails in its entirety and shows as 1 test failed. As assertion 1 failed, it blocked the rest of the line of code from executing. When there are hundreds of tests it is not easy to see from the test results, which of the assertions has failed and which of them would have passed. You would have to scroll through the long logs to know which line of the test has an error and which part of the code needs fixing.

To save our time in future, we are going to separate the test as below.

test("should give sum of two numbers of type string", () => {
  expect(sum("1", "2")).toBe(3);
});

test("should give sum of two numbers of type numbers", () => {
  expect(sum(1,2)).toBe(3);
});
Enter fullscreen mode Exit fullscreen mode

Now if I run the test using the jest command, I will receive the test results as follows

1 Test failed 1 Test passed

From the above you can see that 1 test failed whereas the other test passed, it is easy to focus on the failed behaviour.

Now let's go and fix the code.

function sum(a,b){
  return Number(a) + Number(b);
}
Enter fullscreen mode Exit fullscreen mode

The test passes and how beautiful is to behold those green ticks.

Both Tests passed

The tests should not end there, keep adding more data points to test the code. For example

test("should return number if one of them is undefined", () => {
  expect(sum(undefined,2)).toBe(2);
});
Enter fullscreen mode Exit fullscreen mode

The above test fails and gives the below test results

Image description

You will keep on modifying the code until it passes all the required behaviour for different data inputs. As a result, you will have a code of high quality and whenever the requirement of behaviour changes in future, start with a test and then go on fixing it.

What we did in the last step was similar to TDD (Test Driven Development) - the red, green and refactor method. Write a failing test, then write the minimum code to make it pass; then make it better by refactoring the code. Although in TDD we could further divide the steps of code by first returning a hardcoded number 3, then testing with another set of number inputs which would make the earlier tests fail, and the cycle continues.

Top comments (1)

Collapse
 
alphaolomi profile image
Alpha Olomi

Next post maybe negative tests, like expect(sum("1", "2")).not.toBe(4)