Mocha vs Jasmine in 2018
Posted Apr 5, 2018 | 5 min. (983 words)It’s official: JavaScript is everywhere.
JavaScript has been enabling browsers for years. NodeJS brought it to the server side. TypeScript has wrapped familiar object-oriented, statically-typed syntax around it. Anywhere you look, you’ll find JavaScript: on the client, server, mobile, and embedded systems.
All good software must be tested, and software written in JavaScript is no exception (pun intended.) Many JavaScript test frameworks are available. They offer features such as:
- Test runners
- BDD -Style test suites
- Assertions
- Spies
- Fakes
Mocha vs Jasmine
Let’s take a look at two of the most popular test frameworks, Jasmine and Mocha, with an eye toward their similarities and differences.
Jasmine Jasmine was created around 2008. The documentation describes Jasmine as “batteries included,” meaning that it attempts to provide everything a developer needs in a test framework.
Mocha Mocha is younger than Jasmine, created around 2011. Mocha is not a “complete” test framework, and doesn’t attempt to be. Instead, Mocha covers the basics, and allows developers to extend it with other frameworks.
Common Ground: BDD Tests
At their core, Mocha and Jasmine both offer Behavior-Driven Design (BDD) tests:
describe("My First Test Suite", function() {
it("introduces a test suite", function() {
//assertion here
});
});
This is what Mocha and Jasmine have in common. The describe
function defines a test suite. The it
function implements the BDD method of describing the behavior that a function should exhibit. The first parameter is a plain-English description of the behavior under test. The second parameter is a function that will call assertions that will pass or fail, depending on whether the described behavior was, or was not confirmed. A single describe
test suite can embed multiple calls to the it
function.
The implementations of Mocha and Jasmine diverge beyond this point. Now let’s take a look at their differences.
Mocha and Jasmine differences
Assertions
Assertions are boolean functions that are used to test behavior. Typically, a true
result indicates that a test passed, indicating that the expected behavior is what actually occurred when the test was run.
Jasmine includes an assertion library that uses an expect
-style syntax:
describe("My First Test Suite", function() {
it("introduces a test suite", function() {
expect(true).toBe(true);
});
});
Mocha does not have a built-in assertion library. Developers must use a dedicated assertion library in combination with Mocha. The popular Chai assertion library uses a syntax similar to Jasmine:
describe("My First Test Suite", function() {
it("introduces a test suite", function() {
expect(true).to.equal(true);
});
});
Chai uses a “fluent” syntax, where comparison operators can be chained together:
expect(foo).to.equal('foo') //equality
expect(foo).to.not.equal('foo') //inequality
expect(foo).to.be.a('string') //type assertion
Chai also supports should
-style and “classical” assert
assertions.
Test Doubles / Spies Test double frameworks create test doubles. A test double, or spy, is like a clone of an object. A test double has the same functions as the original object, however, those functions are “stubbed out,” meaning that they don’t do anything. The “stubbed” functions exist so the test double framework can “watch” the double, tracking the calls to its functions.
Jasmine includes a spyOn
method that can be used to create spies:
describe("Spying on an object", function(){
var car, go = null;
//the beforeEach setup function will be called with each run of the suite
beforeEach(function(){
car = {
go: function(value) {
speed = value;
}
};
spyOn(car, 'go'); //creates the spy
car.go(50);
car.go(80);
});
//This test will succeed
it("Called the go function", function(){
expect(car.go).toHaveBeenCalled();
});
//This test will fail- the go function is called twice
it("Called the go function once", function(){
expect(car.go).toHaveBeenCalledTimes(1);
});
});
Once again, Mocha does not include a spy framework. The SinonJS framework is a popular choice for creating spies:
describe("Spying on an object", function(){
var car, go = null;
//the beforeEach setup function will be called with each run of the suite
beforeEach(function(){
car = {
go = function(value) {
speed = value;
}
};
sinon.spy(car, 'go'); //creates the spy
car.go(50);
car.go(80);
});
//This test will succeed
it("Called the go function", function(){
assert(car.go.called);
});
//This test will fail- the go function is called twice
it("Called the go function once", function(){
assert(car.go.calledOnce);
});
});
The overall syntax between Jasmine and SinonJS are similar, however, there is a key difference. The Jasmine spy will not call the original “go” function by default. Only the spy “stub” is called unless .and.callThrough()
is used when creating the spy:
spyOn(car, 'go').and.callThrough()
Sinon, however, will “pass through” the call to the implementation of the spied-on function by default.
Fake Server Test “fakes” are used to isolate a test from external dependencies. Unit tests should not make calls outside their scope to networks or databases. Fakes are used to simulate that behavior without actually making any external calls.
SinonJS is a more complete framework test double framework than Jasmine, including not only spies, but also stubs and fakes. Here is an example of a test using the SinonJS fake server:
before(function () { server = sinon.fakeServer.create(); });
after(function () { server.restore(); });
it("calls callback with deserialized data", function () {
var callback = sinon.spy();
getCustomer(5, callback);
// This is part of the FakeXMLHttpRequest API
server.requests[0].respond(
200,
{ "Content-Type": "application/json" },
JSON.stringify([{ id: 5, FirstName: "Bob", LastName: "Dobbs" }])
);
assert(callback.calledOnce);
});
Jasmine does not include fakes, so the Mocha + SinonJS option is best when you want to fake an HTTP server.
Conclusion
Jasmine comes included with assertions and spies, but that doesn’t necessarily make it the better option. Mocha does one thing, and does it well: BDD test definitions. Other best-of-breed frameworks combine with Mocha to extend it.
The best way to make your choice between Mocha and Jasmine is to try both. Your particular needs, and the nature of the application under test, will make the better choice clear as you experiment. You can combine them, but to keep your tests consistent and readable, I recommend using Jasmine or Mocha+Chai+Sinon, within an application. Good luck!