What is the difference between “assert”, “expect”, and “should” in Chai?
What is the difference between assert
, expect
, and should
? When to use what?
assert.equal(3, '3', '== coerces values to strings');
var foo = 'bar';
expect(foo).to.equal('bar');
foo.should.equal('bar');
The differences are documented there.
The three interfaces present different styles of performing assertions. Ultimately, they perform the same task. Some users prefer one style over the other. This being said, there are also a couple technical considerations worth highlighting:
The assert and expect interfaces do not modify
Object.prototype
, whereas should does. So they are a better choice in an environment where you cannot or do not want to changeObject.prototype
.-
The assert and expect interfaces support custom messages just about everywhere. For instance:
assert.isTrue(foo, "foo should be true"); expect(foo, "foo should be true").to.be.true;
The message "foo should be true" will be output together with the failed assertion if the assertion fails. You don't get the opportunity to set a custom message with the should interface.
(Historical note: for a long time this answer stated that to get a custom message with expect
, you'd have to use a workaround. Aurélien Ribon informed me that passing a message to expect
as a second parameter works. Consequently, there is no need for a workaround. I've not been able to find which version of Mocha started providing support for this message, nor have I been able to find which version of the documentation documented it for the first time.)
Note that assert.isTrue(foo)
, expect(foo).to.be.true
and foo.should.be.true
all output the following if you do not use a custom message, and foo === 1
:
AssertionError: expected 1 to be true
So while the expect and should interface are nicer to read, it is not like one interface is more naturally informative than the other when an assertion fails. This message, which is identical for all three interfaces, does not tell you what exactly you were testing, only that the value you got was 1
but you wanted true
. If you want to know what you were testing, you need to add a message.
I hope this simple examples makes their differences clear
Assert
var assert = require('chai').assert
const foo = 'bar'
const beverages = { tea: [ 'chai', 'matcha', 'oolong' ] };
assert.typeOf(foo, 'string'); // without optional message
assert.typeOf(foo, 'string', 'foo is a string'); // with optional message
assert.equal(foo, 'bar', 'foo equal `bar`');
assert.lengthOf(foo, 3, 'foo`s value has a length of 3');
assert.lengthOf(beverages.tea, 3, 'beverages has 3 types of tea');
In all cases, the assert style allows you to include an optional message as the last parameter in the assert statement. These will be included in the error messages should your assertion not pass.
Note expect and should uses chainable language to construct assertions, but they differ in the way an assertion is initially constructed. In the case of should, there are also some caveats and additional tools to overcome the caveats.
Expect
var expect = require('chai').expect
const foo = 'bar'
const beverages = { tea: [ 'chai', 'matcha', 'oolong' ] };
expect(foo).to.be.a('string');
expect(foo).to.equal('bar');
expect(foo).to.have.lengthOf(3);
expect(beverages).to.have.property('tea').with.lengthOf(3);
Expect allows you to include arbitrary messages to prepend to any failed assertions that might occur.
var answer = 43;
// AssertionError: expected 43 to equal 42.
expect(answer).to.equal(42);
// AssertionError: topic [answer]: expected 43 to equal 42.
expect(answer, 'topic [answer]').to.equal(42);
This comes in handy when being used with non-descript topics such as booleans or numbers.
Should
The should style allows for the same chainable assertions as the expect interface, however it extends each object with a should property to start your chain. This style has some issues when used with Internet Explorer, so be aware of browser compatibility.
var should = require('chai').should() //actually call the function
const foo = 'bar'
const beverages = { tea: [ 'chai', 'matcha', 'oolong' ] };
foo.should.be.a('string');
foo.should.equal('bar');
foo.should.have.lengthOf(3);
beverages.should.have.property('tea').with.lengthOf(3);
Differences between expect and should
First of all, notice that the expect require is just a reference to the expect function, whereas with the should require, the function is being executed.
var chai = require('chai')
const expect = chai.expect
const should = chai.should();
The expect interface provides a function as a starting point for chaining your language assertions. It works on node.js and in all browsers.
The should interface extends Object.prototype to provide a single getter as the starting point for your language assertions. It works on node.js and in all modern browsers except Internet Explorer.