Back to Home

Automated testing with Mocha

Automated testing will be used in further tasks, and it’s also widely used in real projects.

Why do we need tests?

When we write a function, we can usually imagine what it should do: which parameters give which results. During development, we can check the function by running it and comparing the outcome with the expected one. For instance, we can do it in the console. If something is wrong – then we fix the code, run again, check the result – and so on till it works. But such manual “re-runs” are imperfect. When testing a code by manual re-runs, it’s easy to miss something. For instance, we’re creating a function f. Wrote some code, testing: f(1) works, but f(2) doesn’t work. We fix the code and now f(2) works. Looks complete? But we forgot to re-test f(1). That may lead to an error. That’s very typical. When we develop something, we keep a lot of possible use cases in mind. But it’s hard to expect a programmer to check all of them manually after every change. So it becomes easy to fix one thing and break another one. Automated testing means that tests are written separately, in addition to the code. They run our functions in various ways and compare results with the expected.

Behavior Driven Development (BDD)

Let’s start with a technique named Behavior Driven Development or, in short, BDD. BDD is three things in one: tests AND documentation AND examples. To understand BDD, we’ll examine a practical case of development.

Development of “pow”: the spec

describe(“title”, function() { … })

What functionality we’re describing? In our case we’re describing the function pow. Used to group “workers” – the it blocks. it(“use case description”, function() { … })

In the title of it we in a human-readable way describe the particular use case, and the second argument is a function that tests it. assert.equal(value1, value2)

The code inside it block, if the implementation is correct, should execute without errors. Functions assert.* are used to check whether pow works as expected. Right here we’re using one of them – assert.equal, it compares arguments and yields an error if they are not equal. Here it checks that the result of pow(2, 3) equals 8. There are other types of comparisons and checks, that we’ll add later. The specification can be executed, and it will run the test specified in it block. We’ll see that later.

The development flow

The flow of development usually looks like this:

  1. An initial spec is written, with tests for the most basic functionality.

  2. An initial implementation is created.

  3. To check whether it works, we run the testing framework Mocha (more details soon) that runs the spec. While the functionality is not complete, errors are displayed. We make corrections until everything works.

  4. Now we have a working initial implementation with tests.

  5. We add more use cases to the spec, probably not yet supported by the implementations. Tests start to fail.

  6. Go to 3, update the implementation till tests give no errors.

  7. Repeat steps 3-6 till the functionality is ready. So, the development is iterative. We write the spec, implement it, make sure tests pass, then write more tests, make sure they work etc. At the end we have both a working implementation and tests for it. Let’s see this development flow in our practical case. The first step is already complete: we have an initial spec for pow. Now, before making the implementation, let’s use a few JavaScript libraries to run the tests, just to see that they are working (they will all fail).

    The spec in action

    Here in the tutorial we’ll be using the following JavaScript libraries for tests:

  1. The – add third-party libraries and styles for tests.

  2. The