Skip to content
This repository was archived by the owner on May 13, 2019. It is now read-only.

Commit 13b4038

Browse files
committed
doc: add How to write a node test guide
1 parent 1f8666b commit 13b4038

File tree

1 file changed

+137
-0
lines changed

1 file changed

+137
-0
lines changed

test_guide.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# How to write a Node.js test
2+
3+
## What is a test?
4+
5+
A test must be a node script that exercises a specific functionality provided by node and
6+
checks that it behaves as expected. It should return 0 on success, otherwise it will
7+
fail. A test will fail if:
8+
9+
- It exits by calling `process.exit(code)` where `code != 0`
10+
- It exits due to an uncaught exception.
11+
- It never exits. In this case, the test runner will terminate the test because it sets a maximum time limit.
12+
13+
They can be added for multiple reasons:
14+
15+
- When adding new functionality.
16+
- When fixing regression and bugs.
17+
- Expanding test coverage.
18+
19+
20+
## Test structure
21+
22+
Let's analyze this very basic test from the Node.js test suite:
23+
24+
```javascript
25+
1 'use strict';
26+
2 const common = require('../common');
27+
3 const http = require('http');
28+
4 const assert = require('assert');
29+
5
30+
6 const server = http.createServer(common.mustCall((req, res) => {
31+
7 res.end('ok');
32+
8 }));
33+
9 server.listen(common.PORT, () => {
34+
10 http.get({
35+
11 port: common.PORT,
36+
12 headers: {'Test': 'Düsseldorf'}
37+
13 }, common.mustCall((res) => {
38+
14 assert.equal(res.statusCode, 200);
39+
15 server.close();
40+
16 }));
41+
17 });
42+
```
43+
44+
**Lines 1-2**
45+
46+
```
47+
'use strict';
48+
const common = require('../common');
49+
```
50+
51+
These two lines are mandatory and should be included on every test.
52+
The `common` module is a helper module that provides useful tools for the tests.
53+
If for some reason, no functionality from `common` is used, it should still be included like this:
54+
55+
```
56+
require('../common');
57+
````
58+
59+
Why? It checks for leaks of globals.
60+
61+
**Lines 3-4**
62+
63+
```
64+
const http = require('http');
65+
const assert = require('assert');
66+
```
67+
68+
These modules are required for the test to run. Except for special cases, these modules should only include core modules.
69+
The `assert` module is used by most of the tests to check that the assumptions for the test are met.
70+
71+
**Lines 6-17**
72+
73+
This is the body of the test. This test is quite simple, it just tests that an HTTP server accepts `obs-text` characters in the headers of an incoming request. Interesting things to notice:
74+
75+
- The use of `common.PORT` as the listening port. Always use `common.PORT` instead of using an arbitrary value, as it allows to run tests in parallel safely, as they are not trying to reuse the same port another test is already using.
76+
- The use of `common.mustCall` to check that some callbacks/listeners are called.
77+
- The HTTP server is closed once all the checks have run. This way, the test can exit gracefully. Remember that for a test to succeed, it must exit with a status code of 0
78+
79+
## General recommendations
80+
81+
- The use of timers is discouraged, unless we're testing timers. The reasons for this are multiple. Mainly, they are a source of flakiness. For a thorough explanation go [here](https://github.com/nodejs/testing/issues/27).
82+
83+
- Make use of the helpers from the `common` module as much as possible.
84+
85+
One interesting case is `common.mustCall`. The use of `common.mustCall` may avoid the use of extra variables and the corresponding assertions. Let's explain this with a real test from the test suite.
86+
87+
```javascript
88+
'use strict';
89+
var common = require('../common');
90+
var assert = require('assert');
91+
var http = require('http');
92+
93+
var request = 0;
94+
var response = 0;
95+
process.on('exit', function() {
96+
assert.equal(request, 1, 'http server "request" callback was not called');
97+
assert.equal(response, 1, 'http request "response" callback was not called');
98+
});
99+
100+
var server = http.createServer(function(req, res) {
101+
request++;
102+
res.end();
103+
}).listen(common.PORT, function() {
104+
var options = {
105+
agent: null,
106+
port: this.address().port
107+
};
108+
http.get(options, function(res) {
109+
response++;
110+
res.resume();
111+
server.close();
112+
});
113+
});
114+
```
115+
116+
This test could be greatly simplified by using `common.mustCall` like this:
117+
118+
```javascript
119+
'use strict';
120+
var common = require('../common');
121+
var assert = require('assert');
122+
var http = require('http');
123+
124+
var server = http.createServer(common.mustCall(function(req, res) {
125+
res.end();
126+
})).listen(common.PORT, function() {
127+
var options = {
128+
agent: null,
129+
port: this.address().port
130+
};
131+
http.get(options, common.mustCall(function(res) {
132+
res.resume();
133+
server.close();
134+
}));
135+
});
136+
137+
```

0 commit comments

Comments
 (0)