Writing Test Solutions with JavaScript: Mocha and Chai

In this post, I want to cover using two particular libraries as part of the JavaScript testing ecosystem. I’ll be very briefly covering Mocha and Chai. I tend to use these quite a bit and will likely do so in future posts. This post will thus serve as a brief introduction to the tools along with a working example.

As a tester, you may or may not not be tasked with unit testing. The tools that JavaScript developers use for unit testing, however, can also be used for integration and/or system testing. Here I’ll use Mocha and Chai.

Mocha is a test runner that can be executed from Node as well as inside a browser. In a previous post, unrelated to this one, I showed how to use Mocha in a browser. Here I’m going to show how to execute it from Node. Chai is an assertion and expectation library. So we’ll use Mocha to execute our tests and Chai to determine if our tests passed or failed during execution.

Do note that this post conceptually follows on from my previous “Starting Out” post but you can read this as a standalone post as well. I do, however, assume a bit of knowledge on your part. At the very least, make sure you can set up Node and NPM. (See my Setting up WebDev page if you need help.)

Create and Initialize the Project

To get started, create a new project.

$ mkdir project-dir
$ cd project-dir

Now let’s initialize our project with NPM.

$ npm init

That command invokes NPM to generate a package.json inside the current directory. During the process, it will ask you some questions. Most of them are fairly self-explanatory. You can always just press ‘Enter’ to accept the default. You will be able to edit the package.json file later if you want to change your mind on some settings.

This package file contains all the information needed for NPM to manage your new package. You might be saying: “My package? What package? Did I create a package?” In fact, you did. The presence of package.json, and the information within it, is what marks the folder as a package. This JSON data contains the name of your package, which other packages your package depends on, and whether these dependencies are necessary only in runtime or during development.

Create a Stand-In Application

We’re going to need a mini-application to test. To keep this as simple as possible to start with, I’m going to have you create a library directory where you can store some JavaScript code. It’s this code that we’ll run our tests against.

$ mkdir lib

Within that directory create a file called stardate.js and put the following in it:

Don’t worry too much at all about the code. I just provide this as a means for something to execute.

Install the Libraries

To finish the initialization of the project, you just need to install the tools that we will use: Mocha and Chai. To do so, just input the following command:

$ npm install --save-dev mocha chai

This command will install Mocha and Chai locally to your project. This means that it will download the packages and all their dependencies, compile them if necessary, and store the result in a node_modules directory inside the project. In fact, you should now have node_modules in your project that contains a folder for Mocha and another for Chai.

Also, if you take a look, you’ll notice that the package.json file has changed; now it contains a “devDependencies” section. This is because I specified the –save-dev parameter in the command when installing the libraries. That qualifier to the command means that, after downloading and installing the packages, NPM will modify the package.json file to specify that your package depends on the Mocha and Chai packages during development time. That means anyone else who wants to work on your project on their machine can just do this:

$ npm install

As far as which actual library version you will be using, do note that, in this case, NPM will install the latest version that is compatible with the ones specified inside package.json. At the time I wrote this post, here’s what my section looked like:

The ^ character at the beginning specifies that NPM will install the latest version of the package that does not change the leftmost nonzero digit.

While we’re looking at the package.json file, let’s change the part about testing. Update the file as such:

This is going to let us run Mocha quite a bit easier because you won’t have to type the path to Mocha. Instead, NPM will resolve the path for us. Specifically, with this change, you can invoke Mocha in the following way:

$ npm test

This command will inspect the “scripts” section of package.json and execute the command specified in “test”. NPM is smart enough to figure out that you want to execute a tool installed as a local package, so it will temporarily modify the PATH to include node_modules/.bin/. In this case, that path would be node_modules/.bin/mocha.

Creating the Tests

First let’s create a test directory.

$ mkdir test

Now create a file called stardate-test.js in that directory and put the following in it:

This is a test file but what I have here is not yet a test. I’m using the describe function, provided by Mocha, to structure what is going to be my test specification. The describe function creates a new test suite for Mocha. In this context, a “test suite” is just a grouping of tests with a natural language description. As you can see above, the description is provided as the first parameter, and the actual contents of the test suite are going to be supplied inside the function that is used as the second parameter.

One quick side point here: Am I ‘describing’ the feature here or the component? Technically, it could be both. In a pure TDD context, if the above was being used for unit testing, this would be describing the component. In a BDD context, this is describing a feature. This is important to realize because what I’m showing you in this post is essentially going to be hitting the code directly and could be considered a unit test. If you were to put a front-end web page in place that called the stardate code, then you would probably use front-end drivers like Selenium.

Now let’s update our specification as such:

Like describe, the context function takes a natural language description and a function. But what does this mean? One way of thinking about test test specifications is that you can consider a particular context for each scenario of a feature. A scenario defines a different execution path of the same feature. Since, ideally, one feature defines only one operation on the system, different scenarios can vary only in their setup or in the inputs of the operation.

From the technical standpoint of Mocha, context is a just an alias of describe. They are exactly the same thing as far as Mocha is concerned: an encapsulating function for tests. Both describe and context can be nested to whatever degree seems to make sense for your particular description needs in your test specification.

Now let’s add a bit more to our test specification:

Finally! We’ve created our first test cases using the Mocha it function. Just like describe and context, the it function takes a natural language description and a function. If you’ve used any sort of xSpec style testing library before, none of the formatting here, save the JavaScript-specific structure, should be a surprise to you.

Incidentally, what I’ve been doing so far is using the BDD interface of Mocha. The Mocha documentation on interfaces will provide you with information about some different approaches you can take.

Create Test Logic and Expectations

Now let’s put some logic in the tests that will execute the application and get us some result. Add the following lines to the respective tests:

This is not a bad start but we don’t actually have a test yet because we don’t make an observation and comparison. Here’s where we’re going to use Chai. To do this, add the following at the top of your test specification:

This just make sure that Chai is available but then I also set Chai to use its expectation interface. Chai, much like Mocha, has different API interfaces you can rely on. I’m using the Chai BDD API but you can also use a Chai Assert API. You can take a look at the Chai Styles for more information, including the use of the Should API which some people like.

Now let’s add some expectations to our test code:

You can now run the tests:

$ npm test

This will get you some nice output and, what is of importance for some, you’ll notice that your test report actually seems fairly readable:

calculating stardates
  for the original series
    will calculate a valid stardate
  for the next generation
    will calculate a valid stardate

There is a lot of test philosophy that now can take place, such as: “Should these tests be worded so vaguely?” or “Should the actual stardate input used be part of the description?” Those are all good discussions to have. Here I’m just focusing on getting you up to speed with the mechanics so that you can have those discussions.

Wrapping Up

From a structural point fo view, do make sure to keep in mind that with the context functions, you are describing different scenarios (what happens with different inputs), while for the it functions, you are using a specific input example and — eventually — the expected result (i.e., assertion and/or expectation). The operating heuristic for these xSpec style test libraries is to use context to define scenarios, describe to
define features and actions, and it for actual tests.

At this point you have at least a working example of using Mocha and Chai, along with some pointers to the documentation for both libraries. There are other libraries out there that people use. Obviously you have to pick and choose a bit, but Mocha and Chai have a lot of inertia in the community. However, you may be thinking: “Great, but these are JavaScript tools for testing JavaScript, right? What if I’m not using JavaScript?”

Well, the good news is your applications are probably using JavaScript somewhere. So knowing JavaScript and its ecosystem of test tools can help. Beyond that, however, I’ve often used Ruby for testing Java and .NET applications by simply driving a browser or an API service with Ruby testing tools. The same can be done with JavaScript. In a future post, I’ll talk about how to extend the knowledge here into the domain of testing web applications, regardless of what the back-end business logic is written in.

About Jeff Nyman

Anything I put here is an approximation of the truth. You're getting a particular view of myself ... and it's the view I'm choosing to present to you. If you've never met me before in person, please realize I'm not the same in person as I am in writing. That's because I can only put part of myself down into words. If you have met me before in person then I'd ask you to consider that the view you've formed that way and the view you come to by reading what I say here may, in fact, both be true. I'd advise that you not automatically discard either viewpoint when they conflict or accept either as truth when they agree.
This entry was posted in Automation, JavaScript, Test Solutions. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *