How to write JavaScript unit tests with Mocha
In part one of this series on JavaScript unit testing, we covered some guiding principles and common excuses. Let's continue with part two, where we'll write unit tests using Mocha.
Get Visual Studio
First of all, you need Visual Studio. If you don't have it already, you can download a free edition called Visual Studio 2013 Express for Web. If you're a student, check with your administrators to see if your college is enrolled in DreamSpark. If so, you'll have free access on the DreamSpark site to paid versions of Visual Studio such as the Professional edition. This gives you more features. If you're a startup, enroll in BizSpark to get a MSDN license for 3 years. This also gives you paid versions of Visual Studio such as Professional and Ultimate.
Create a web site and add unit tests
- Download the following code sample: 5025.Calculator.zip. Right click on it, and choose Extract All.
- In Visual Studio, go to File -> Open Web Site. Select the Calculator folder you unzipped in step 1.
- Launch the website by choosing Debug -> Start Debugging. Or, you can just hit F5. This is the Mocha test runner and you'll see the output for a single unit test. It tests the
add
function on theCalculator
object. - Close the browser window that just launched.
- In Visual Studio, open
index.html
,js/calculator.js
, andtest/calculator-tests.js
. - In
index.html
, you'll see the unit test framework Mocha referenced. You'll also see a reference to Expect. That's an assertion library. It then references the JavaScript being tested,calculator.js
, and then the unit tests themselves,calculator-tests.js
. - In
calculator.js
, you'll see a JavaScript IIFE which defines aCalculator
constructor and theadd
function. - In
calculator-tests.js
you'll see 3 sections. Thedescribe
at the top defines the test suite. ThebeforeEach
sets up any necessary state. Perhaps your unit test relies on things being set up a certain way. Do that inbeforeEach
. The remainingdescribe
function describes the specification. It corresponds to a particular feature. The call to theit
function defines what the test should do. Be as explicit as possible. Lastly,expect
asserts what the result of the test should be. - Let's add a new test. In
calculator-tests.js
, copy this code for thesubtract
test and paste it below theadd
test:
describe("Subtract", function () {
it("should return the difference of both operands", function () {
expect(calculator.subtract(5, 3)).to.be(2);
});
});
- Hit F5 to run the tests, and it should fail. This is called TDD: Test-Driven Development. In TDD, you write your unit test first, run it to verify it fails, and only then implement the code you're testing. This prevents you from accidentally writing a unit test which always passes, giving you a false sense of safety.
- In
calculator.js
, create thissubtract
function. Note that the function body is incorrect. That's on purpose:
Calculator.prototype.subtract = function (operand1, operand2) {
return operand1 + operand2;
};
- Run the tests again by hitting F5. This time you'll get a different error.
- Change the
subtract
function incalculator.js
to correctly implement subtraction:
Calculator.prototype.subtract = function (operand1, operand2) {
return operand1 - operand2;
};
- Run the tests a final time by hitting F5. This time both tests should pass. If you don't notice a difference, it could be because your web page is cached. Reload the page by hitting Control-R.
Commentary
Recall the principles of unit testing from part one in this series. How do the above unit tests stack up?
- The unit tests are predictable. We pass in static arguments and everything is reproducible.
- It's obvious when the unit tests pass or fail.
- The tests are self-documenting. A quick look at the
Add
unit test tells us that "Add should return the sum of both operands". We know what that means without having to look anything up. - The unit tests have a single responsibility and only test one thing at a time.
- When the tests fail, we get useful error messages.
- They don't test multiple components, so they're not integration tests.
How about the excuses we listed in part one? Were these tests too hard to write, or too cumbersome? Once you learn how tests are written, they should be pretty simple especially when compared with debugging code without unit tests.
Want to learn more? Take a look at the Pluralsight course Front-end First: Testing and Prototyping JavaScript Apps by Elijah Manor. That's where this example is from.
In part three of this series, we'll see how to use the Chutzpah unit test runner in Visual Studio.