DEV Community

Cover image for Test-Driven Development
benlongcp
benlongcp

Posted on

Test-Driven Development

Basics of test-driven development with Mocha/chai

Writing tests is an effective way to implement code that accomplishes specific tasks. Unit testing allows a developer to create a way to ensure the program is behaving as expected.

Testing frameworks are sets of guidelines and operations that collect results of tests and provide them to the tester. Mocha is such a testing framework.

An assertion library contains sets of functions and methods to implement tests. These are what actually test the code to see if it's working. Chai is one of several assertion libraries.

Test driven development (TDD) performs specific checks on the code's functionality to see if the code behaves as expected. For example, checking to see that a function returns whether two values are equal.

Behavior-Driven Development (BDD) focuses more on what an end-user would expect the code to be able to do. For example, when they get a new email, they should see it in their inbox.

Chai has three assertion libraries that it uses. The first is Assert. Assert is a function-based assertion style, TDD as noted above, it is not chainable, and doesn't modify the object it's checking. It can include an optional message as the final parameter to indicate to the tester what the result should be.

Expect is a BDD style assertion library. It is designed to be more readable than Assert. Thus, it is a chain-able assertion style with object getters to create "sentences" with easier to understand language. They don't modify the object they're accessing. Expects can include an optional message as the final parameter

Should is also a BDD style assertion library. It uses the same chainable language as Expect, but differs in that it extends an object with a "should" property, and modifies that object's prototype. The actual function is invoked . Finally, it does not allow for custom messages

Writing a simple test for some code.

In this example, I'm using node.js to run tests with Mocha. Mocha looks for a test folder in the main directory of the project and a test.js file within that.

Image description

Here is a simple function that adds two numbers:

//here is a simple function that adds two numbers
export default function (a, b) {
    return a + b
}
Enter fullscreen mode Exit fullscreen mode

I'm exporting this function for another script to be able to import. In my test/test.js, I'll import the function from the test.js in the main directory.

//test/test.js

//imports tests.js from the parent directory
import add from '../tests.js';
// import { expect } from 'chai';
import { assert } from 'chai';

    it('should return 5', function() {
      assert(add(2, 3) === 5)
    })
Enter fullscreen mode Exit fullscreen mode

And indeed when we run npm test in the terminal, we get a beautiful green checkmark.

Image description

But what if we want our add function to do a little more? What if we're making a game and the numbers going into our add function are two dice rolls that will allow the character to, say, jump over a ravine. Maybe when we roll doubles we want a critical success so their chances of jumping all the way are increased. (For this example we'll presume snake-eyes is always an automatic failure.

To write a test for this, we might say the following:

//when the numbers are the same, multiply them
    it("should return a square on doubles", function() {
      assert(add(3, 3) === 9)
    })
Enter fullscreen mode Exit fullscreen mode

And when we run the test...

Image description

Womp womp.

So now we have to modify the incoming function to make the test pass, which we can do thusly:

//here is a function that adds two numbers
//and squares them when they're equal
export default function (a, b) {
  if (a === b){
    return a * b
  }
    return a + b
}

Enter fullscreen mode Exit fullscreen mode

And behold, the test now passes:

Image description

Image description

The real power in unit testing and testing in general is the ability to create suites of tests and so allowing the programmer to focus on the individual elements of functionality that eventually cohese into a final product. They allow for traversal of complex implementations in discrete pieces that are more manageable than a vast empty repository.

sources:
[https://www.chaijs.com/guide/styles/]
[https://medium.com/@dezsays/understanding-chai-a-comprehensive-guide-to-the-javascript-assertion-library-a382d5617832]

Top comments (0)