Test framework Mocha example tutorial
Mocha
(Pronounced “Mocha”) was born in 2011 and is now one of the most popular JavaScript testing frameworks. It can be used in both browser and Node environments.
The so-called “test framework” is a tool for running tests. Through it, you can add tests for JavaScript applications to ensure the quality of the code.
This article comprehensively introduces how to use
Mocha
it so that you can get started easily.
If you didn’t know anything about testing before, this article can also be used as an introduction to JavaScript unit testing.
It should be noted that, in addition to Mocha, a similar testing framework as well as
Jasmine
,
Karma
,
Tape
etc., is also worth studying.
1. Installation
I wrote a sample library for this article
Mocha-demos
, please install this library first.
$ git clone https://github.com/ruanyf/mocha-demos.git
If Git is not installed on your computer, you can directly download the zip archive and decompress it.
Then, enter the
mocha-demos
directory and install dependencies (you must have Node on your computer).
$ cd mocha-demos $ npm install
The above code will be installed inside the directory
Mocha
. For the convenience of operation, please install it in a comprehensive environment
Mocha
.
$ npm install --global mocha
Second, the writing of the test script
Mocha
The role of is to run test scripts, you must first learn to write test scripts.
The so-called “test script” is a script used to test the source code.
Below is
add.js
the code
of an addition module
.
// add.js function add(x, y) { return x + y; } module.exports = add;
To test whether the addition module is correct, it is necessary to write a test script.
Usually, the test script has the same name as the source script to be tested, but the suffix is
.test.js
(means test) or
.spec.js
(means specification).
For example,
add.js
the name of the test script is
add.test.js
.
// add.test.js var add = require('./add.js'); var expect = require('chai').expect; describe('加法函数的测试', function() { it('1 加 1 应该等于 2', function() { expect(add(1, 1)).to.be.equal(2); }); });
The above code is the test script, which can be executed independently.
The test script should include one or more
describe
blocks, and each
describe
block should include one or more
it
blocks.
describe
Blocks are called “test suites” and represent a set of related tests.
It is a function, the first parameter is the name of the test suite (“addition function test”), and the second parameter is a function that is actually executed.
it
A block is called a “test case”, which represents a single test and is the smallest unit of test.
It is also a function. The first parameter is the name of the test case (“1 plus 1 should be equal to 2”), and the second parameter is an actual function to be executed.
Three, the usage of assertion library
In the above test script, there is an assertion.
expect(add(1, 1)).to.be.equal(2);
The so-called “assertion” is to judge whether the actual execution result of the source code is consistent with the expected result, and throw an error if it is inconsistent.
The above assertion means
add(1, 1)
that the result of the
call
should be equal to 2.
All test cases (it blocks) should contain one or more assertions. It is the key to writing test cases. The assertion function is implemented by the assertion library. Mocha itself does not have an assertion library, so the assertion library must be introduced first.
var expect = require('chai').expect;
There are many kinds of assertion libraries, and Mocha does not limit which one is used.
The assertion library introduced by the above code is
chai
and specifies the
expect
assertion style to
use it
.
expect
The advantage of assertions is that they are very close to natural language. Here are some examples.
// 相等或不相等 expect(4 + 5).to.be.equal(9); expect(4 + 5).to.be.not.equal(10); expect(foo).to.be.deep.equal({ bar: 'baz' }); // 布尔值为true expect('everthing').to.be.ok; expect(false).to.not.be.ok; // typeof expect('test').to.be.a('string'); expect({ foo: 'bar' }).to.be.an('object'); expect(foo).to.be.an.instanceof(Foo); // include expect([1,2,3]).to.include(2); expect('foobar').to.contain('foo'); expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo'); // empty expect([]).to.be.empty; expect('').to.be.empty; expect({}).to.be.empty; // match expect('foobar').to.match(/^foo/);
Basically, the
expect
assertion is written in the same way.
The head is
expect
the method, the tail is asserted method, for example
equal
,
a
/
an
,
ok
,
match
and so on.
Use
to
or
to.be
connect
between the two
.
If the
expect
assertion is not true, an error will be thrown.
In fact, as long as no errors are thrown, the test case will pass.
it('1 加 1 应该等于 2', function() {});
In the above test case, there is no code inside. Since no error was thrown, it will still pass.
Fourth, the basic usage of Mocha
Once you have the test script, you can run it with Mocha.
Please enter the
demo01
subdirectory and execute the following command.
$ mocha add.test.js 加法函数的测试 ✓ 1 加 1 应该等于 2 1 passing (8ms)
The above running results indicate that the test script passed the test. There is only 1 test case in total, which takes 8 milliseconds.
mocha
The command is followed by the path and file name of the test script, and multiple test scripts can be specified.
$ mocha file1 file2 file3
Mocha runs
test
test scripts in subdirectories by
default
.
Therefore, the test script is usually placed in the
test
directory and then executed
mocha
without parameters.
Please enter the
demo02
subdirectory and run the following command.
$ mocha 加法函数的测试 ✓ 1 加 1 应该等于 2 ✓ 任何数加0应该等于自身 2 passing (9ms)
At this time, you can see that
test
the test script in the subdirectory has been executed.
However, if you open the
test
sub-directory, you will find that there is another
test/dir
sub-directory
below
, and there is a test script in it
multiply.test.js
, which has not been executed.
It turns out that by default, Mocha only executes
test
the test cases of the first level under the subdirectory, and does not execute the use cases of the lower levels.
In order to change this behavior,
--recursive
parameters
must be added
. At this time,
test
all test cases under the sub-directory-no matter which level they are on-will be executed.
$ mocha --recursive 加法函数的测试 ✓ 1 加 1 应该等于 2 ✓ 任何数加0应该等于自身 乘法函数的测试 ✓ 1 乘 1 应该等于 1 3 passing (9ms)
Five, wildcard
When specifying a test script on the command line, you can use wildcards to specify multiple files at the same time.
$ mocha spec/{my,awesome}.js $ mocha test/unit/*.js
The first line of command above specifies the execution
spec
of the
my.js
sum
under the directory
awesome.js
.
The second command line specifies
test/unit
all js files in the
execution
directory.
In addition to using Shell wildcards, you can also use Node wildcards.
$ mocha 'test/**/*.@(js|jsx)'
The above code specifies to run
the test script in
test
any subdirectory under the directory with the file suffix name
js
or
jsx
.
Note that Node wildcards must be enclosed in single quotes, otherwise the asterisk (
*
) will be interpreted by the Shell first.
The Node wildcard in the above line, if you use the Shell wildcard instead, it should be written as follows.
$ mocha test/{,**/}*.{js,jsx}
Six, command line parameters
In addition to the previous introduction
--recursive
, Mocha can also add other command line parameters.
Please
demo02
run the following command
in the
subdirectory to check the effect.
6.1 –help, -h
--help
Or
-h
parameters, used to view all the command line parameters of Mocha.
$ mocha --help
6.2 –reporter, -R
--reporter
The parameter is used to specify the format of the test report, the default is the
spec
format.
$ mocha # 等同于 $ mocha --reporter spec
In addition to the
spec
format, the official website also provides many other
report formats
.
$ mocha --reporter tap 1..2 ok 1 加法函数的测试 1 加 1 应该等于 2 ok 2 加法函数的测试 任何数加0应该等于自身 # tests 2 # pass 2 # fail 0
The above is
tap
the display result
of the
format report.
--reporters
Parameters can display all built-in report formats.
$ mocha --reporters
Using the
mochawesome
module, you can generate beautiful HTML format reports.
$ npm install --save-dev mochawesome $ ../node_modules/.bin/mocha --reporter mochawesome
In the above code, the
mocha
command uses the version
mochawesome
installed in the project
, not the version installed globally, because the
module is installed in the project.
Then, the test result report is
mochaawesome-reports
generated
in the
subdirectory.
6.3 –growl, -G
Open the
--growl
parameter, the test result will be displayed on the desktop.
$ mocha --growl
6.4 –watch, -w
--watch
The parameter is used to monitor the specified test script.
As long as the test script changes, Mocha will run automatically.
$ mocha --watch
After the above command is executed, it will not exit.
You can open another terminal window and modify
test
the test script under the directory
add.test.js
, such as deleting a test case. Once saved, Mocha will automatically run it again.
6.5 –bail, -b
--bail
The parameter specifies that as long as one test case fails, the execution of the following test cases will be stopped.
This
is useful
for
continuous integration
.
$ mocha --bail
6.6 –grep, -g
--grep
The parameter is used to search for the name of the test case (that
it
is, the first parameter of the block), and then only execute the matching test case.
$ mocha --grep "1 加 1"
The above code only tests the test cases whose name contains “1 plus 1”.
6.7 –invert, -i
--invert
The parameter means that only test scripts that do not meet the conditions will be run and must be used in conjunction with the
--grep
parameter.
$ mocha --grep "1 加 1" --invert
Seven, the configuration file mocha.opts
Mocha allows you to
test
place configuration files
under the
directory
mocha.opts
and write command line parameters in it.
Please enter the
demo03
directory
first
and run the following command.
$ mocha --recursive --reporter tap --growl
The above command has three parameters
--recursive
,
--reporter tap
,
--growl
.
Then, write these three parameters to
test
the
mocha.opts
file in the
directory
.
--reporter tap --recursive --growl
Then, the execution
mocha
can achieve the same effect as the first line of command.
$ mocha
If the test case is not stored in the test subdirectory, you can
mocha.opts
write the following content.
server-tests --recursive
The above code specifies
server-tests
the test script in the
running
directory and its subdirectories.
Eight, ES6 test
If the test script is written in ES6, you need to transcode with Babel before running the test.
Enter the
demo04
directory, open the
test/add.test.js
file, you can see that this test case is written in ES6.
import add from '../src/add.js'; import chai from 'chai'; let expect = chai.expect; describe('加法函数的测试', function() { it('1 加 1 应该等于 2', function() { expect(add(1, 1)).to.be.equal(2); }); });
ES6 transcoding requires Babel to be installed.
$ npm install babel-core babel-preset-es2015 --save-dev
Then, under the project directory, create a new
.babelrc
configuration file.
{ "presets": [ "es2015" ] }
Finally, use
--compilers
parameters to specify the transcoder of the test script.
$ ../node_modules/mocha/bin/mocha --compilers js:babel-core/register
In the above code, the
--compilers
parameter is followed by a string separated by a colon. The left side of the colon is the file suffix name, and the right side is the name of the module used to process this type of file.
The above code indicates that before running the test, first use the
babel-core/register
module to process the
.js
file.
Since the transcoder here is installed in the project, you need to use the Mocha installed in the project; if the transcoder is installed globally, you can use the global Mocha.
Here is another example, using Mocha to test CoffeeScript scripts.
Before testing, first convert the
.coffee
file to a
.js
file.
$ mocha --compilers coffee:coffee-script/register
Note that Babel does not
Object.assign
transcode
global objects such as Iterator, Generator, Promise, Map, Set, and some global object methods (for example
) by
default
.
If you want to transcode these objects, you must install it
babel-polyfill
.
$ npm install babel-polyfill --save
Then, add a line to the head of your script.
import 'babel-polyfill'
Nine, asynchronous testing
Mocha defaults that each test case is executed for a maximum of 2000 milliseconds. If no results are obtained by that time, an error will be reported.
For test cases involving asynchronous operations, this time is often not enough, and the
timeout threshold
needs to be
specified
with
-t
or
--timeout
parameters.
Go to the
demo05
subdirectory and open the test script
timeout.test.js
.
it('测试应该5000毫秒后结束', function(done) { var x = true; var f = function() { x = false; expect(x).to.be.not.ok; done(); // 通知Mocha测试结束 }; setTimeout(f, 4000); });
For the above test case, it takes 4000 milliseconds before there is a running result.
Therefore, you need to use
-t
or
--timeout
parameters to change the default timeout setting.
$ mocha -t 5000 timeout.test.js
The above command specifies the timeout limit of the test as 5000 milliseconds.
In addition, there is a
done
function in the
above test case
.
it
When the block is executed, a
done
parameter is
passed in
. When the test is over, this function must be called explicitly to tell Mocha that the test is over.
Otherwise, Mocha will not know whether the test is over and will wait until the timeout error is reported.
You can delete this line and try.
By default, Mocha will highlight test cases that exceed 75 milliseconds. You can use
-s
or
--slow
adjust this parameter.
$ mocha -t 5000 -s 1000 timeout.test.js
The above command specifies to highlight test cases that take more than 1000 milliseconds.
Below is another example of asynchronous testing
async.test.js
.
it('异步请求应该返回一个对象', function(done){ request .get('https://api.github.com') .end(function(err, res){ expect(res).to.be.an('object'); done(); }); });
Run the following command, you can see that this test will pass.
$ mocha -t 10000 async.test.js
In addition, Mocha has built-in support for Promises, allowing you to return Promises directly, wait until its state changes, and then execute the assertion without explicitly calling the
done
method.
Please see
promise.test.js
.
it('异步请求应该返回一个对象', function() { return fetch('https://api.github.com') .then(function(res) { return res.json(); }).then(function(json) { expect(json).to.be.an('object'); }); });
10. Hooks for test cases
In Mocha
describe
among block, four hooks test
before()
cases:
after()
, ,
beforeEach()
and
afterEach()
.
They will be executed at the specified time.
describe('hooks', function() { before(function() { // 在本区块的所有测试用例之前执行 }); after(function() { // 在本区块的所有测试用例之后执行 }); beforeEach(function() { // 在本区块的每个测试用例之前执行 }); afterEach(function() { // 在本区块的每个测试用例之后执行 }); // test cases });
Enter the
demo06
subdirectory, you can see the following two examples.
The first is
beforeEach
the example
beforeEach.test.js
.
// beforeEach.test.js describe('beforeEach示例', function() { var foo = false; beforeEach(function() { foo = true; }); it('修改全局变量应该成功', function() { expect(foo).to.be.equal(true); }); });
The above code
beforeEach
will
it
execute before, it will modify global variables.
Another example
beforeEach-async.test.js
is to demonstrate how
beforeEach
to use asynchronous operations in it.
// beforeEach-async.test.js describe('异步 beforeEach 示例', function() { var foo = false; beforeEach(function(done) { setTimeout(function() { foo = true; done(); }, 50); }); it('全局变量异步修改应该成功', function() { expect(foo).to.be.equal(true); }); });
11. Test case management
There are many test cases for large projects.
Sometimes, we want to run only a few of them, then we can use the
only
method.
Both
describe
blocks and
it
blocks allow
only
methods to
be called
, meaning that only a certain test suite or test case is run.
Enter the
demo07
subdirectory, and the test script
test/add.test.js
is used
only
.
it.only('1 加 1 应该等于 2', function() { expect(add(1, 1)).to.be.equal(2); }); it('任何数加0应该等于自身', function() { expect(add(1, 0)).to.be.equal(1); });
In the above code, only
only
test cases
with
methods will run.
$ mocha test/add.test.js 加法函数的测试 ✓ 1 加 1 应该等于 2 1 passing (10ms)
In addition, there are
skip
methods for skipping the specified test suite or test case.
it.skip('任何数加0应该等于自身', function() { expect(add(1, 0)).to.be.equal(1); });
The test case of the above code will not be executed.
12. Browser test
In addition to running on the command line, Mocha can also be run in a browser.
First, use the
mocha init
command to generate the initialization file in the specified directory.
$ mocha init demo08
Running the above command will
demo08
generate
index.html
files
in the
directory
, as well as supporting scripts and style sheets.
<!DOCTYPE html> <html> <body> <h1>Unit.js tests in the browser with Mocha</h1> <div id="mocha"></div> <script src="mocha.js"></script> <script> mocha.setup('bdd'); </script> <script src="tests.js"></script> <script> mocha.run(); </script> </body> </html>
Then, create a new source code file
add.js
.
// add.js function add(x, y) { return x + y; }
Then, this document, as well as the assertion library
chai.js
, added
index.html
.
<script> mocha.setup('bdd'); </script> <script src="add.js"></script> <script src="http://chaijs.com/chai.js"></script> <script src="tests.js"></script> <script> mocha.run(); </script>
Finally,
tests.js
write a test script in it.
var expect = chai.expect; describe('加法函数的测试', function() { it('1 加 1 应该等于 2', function() { expect(add(1, 1)).to.be.equal(2); }); it('任何数加0等于自身', function() { expect(add(1, 0)).to.be.equal(1); expect(add(0, 0)).to.be.equal(0); }); });
Now, when you open
index.html
it
in the browser
, you can see the running result of the test script.
13. Generate specification files
Mocha supports the generation of specification files from test cases.
Go to the
demo09
subdirectory and run the following command.
$ mocha --recursive -R markdown > spec.md
The above command
test
generates a specification file
based
on all test scripts in the directory
spec.md
.
-R markdown
The parameter specifies that the specification report is in markdown format.
If you want to generate a report in HTML format
spec.html
, use the following command.
$ mocha --recursive -R doc > spec.html
(over)