A better life starts with testing
A programmer who doesn't write automated test cases is not a good test engineer. We encourage all projects to establish complete automated test cases from the very beginning. As the project develops, the initial investment will be returned hundreds of times.
Let's continue the example from the previous section and look at how to write a test case using fibjs.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21const http = require('http');
const path = require('path');
var hello_server = {
'/:name(fibjs.*)': (req, name) => {
req.response.write('hello, ' + name + '. I love you.');
},
'/:name': (req, name) => {
req.response.write('hello, ' + name);
}
};
var root_server = {
'/hello': hello_server,
'/bonjour': hello_server,
'*': http.fileHandler(path.join(__dirname, 'web'))
};
var svr = new http.Server(8080, root_server);
svr.start();
an empty test frame
Let’s start with a basic testing framework:
1
2
3
4
5
6
7
8
9
10var test = require('test');
test.setup();
describe('hello, test', () => {
it('a empty test', () => {
});
});
test.run();
After saving it as test.js
, and executing it on the command line fibjs test.js
, you will see the following output, and a basic test framework is written.
1
2
3
4 hello, test
√ a empty test
√ 1 tests completed (0ms)
Start testing the server
Because we need to test the http server, we need to start the server first. The test case will make a request to the server and then test the request result to determine whether the server meets the requirements:
1
2
3
4
5
6
7
8
9
10
11
12
13
14var test = require('test');
test.setup();
var http = require('http');
describe('hello, test', () => {
it('hello, fibjs', () => {
var r = http.get('http://127.0.0.1:8080/hello/fibjs');
assert.equal(r.statusCode, 200);
assert.equal(r.data.toString(), 'hello, fibjs. I love you.');
});
});
test.run();
In this code, we determine whether the server logic is normal by verifying whether the result of http.get is the result we expect. Following this example, we can quickly complete a set of tests and optimize the code at the same time:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30var test = require('test');
test.setup();
var http = require('http');
function test_get(url, rep) {
var r = http.get('http://127.0.0.1:8080' + url);
assert.equal(r.statusCode, 200);
assert.equal(r.data.toString(), rep);
}
describe('hello, test', () => {
it('hello, fibjs', () => {
test_get('/hello/fibjs', 'hello, fibjs. I love you.');
});
it('hello, fibjs*', () => {
test_get('/hello/fibjs-great', 'hello, fibjs-great. I love you.');
});
it('hello, JavaScript', () => {
test_get('/hello/JavaScript', 'hello, JavaScript');
});
it('hello, v8', () => {
test_get('/hello/v8', 'hello, v8');
});
});
test.run();
Use case group management
Next, let's add the test of bonjour. Although bonjour and hello are the same set of services, because the path has changed, we also need to verify the correctness of the service. This time, in order to better manage the use cases, we performed the test cases Grouping, at the same time, because the test contents of hello and bonjour are the same, we optimized the code again and used the same set of code to test the two sets of services:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37var test = require('test');
test.setup();
var http = require('http');
function test_get(url, rep) {
var r = http.get('http://127.0.0.1:8080' + url);
assert.equal(r.statusCode, 200);
assert.equal(r.data.toString(), rep);
}
describe('hello, test', () => {
function test_hello(hello) {
describe(hello + ' test', () => {
it('fibjs', () => {
test_get('/' + hello + '/fibjs', 'hello, fibjs. I love you.');
});
it('fibjs*', () => {
test_get('/' + hello + '/fibjs-great', 'hello, fibjs-great. I love you.');
});
it('JavaScript', () => {
test_get('/' + hello + '/JavaScript', 'hello, JavaScript');
});
it('v8', () => {
test_get('/' + hello + '/v8', 'hello, v8');
});
});
}
test_hello('hello');
test_hello('bonjour');
});
test.run();
By grouping use cases, we can view the test results more clearly, and we can also easily skip and test a group of use cases separately to speed up development and testing. Here are the results from this round of testing:
1
2
3
4
5
6
7
8
9
10
11
12
13 hello, test
hello test
√ fibjs
√ fibjs*
√ JavaScript
√ v8
bonjour test
√ fibjs
√ fibjs*
√ JavaScript
√ v8
√ 8 tests completed (3ms)
According to our server design, we also have a set of static file services. Following the above example, I believe you can quickly write this part of the test cases.
One click test
After the above introduction, we can quickly establish test cases. But in order to use this test script, the server must be started first, which is very inconvenient. We hope that running test.js
can complete the test directly. We can achieve this with the following code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43var test = require('test');
test.setup();
var http = require('http');
var coroutine = require('coroutine');
coroutine.start(() => {
run('./main.js');
});
coroutine.sleep(100);
function test_get(url, rep) {
var r = http.get('http://127.0.0.1:8080' + url);
assert.equal(r.statusCode, 200);
assert.equal(r.data.toString(), rep);
}
describe('hello, test', () => {
function test_hello(hello) {
describe(hello + ' test', () => {
it('fibjs', () => {
test_get('/' + hello + '/fibjs', 'hello, fibjs. I love you.');
});
it('fibjs*', () => {
test_get('/' + hello + '/fibjs-great', 'hello, fibjs-great. I love you.');
});
it('JavaScript', () => {
test_get('/' + hello + '/JavaScript', 'hello, JavaScript');
});
it('v8', () => {
test_get('/' + hello + '/v8', 'hello, v8');
});
});
}
test_hello('hello');
test_hello('bonjour');
});
process.exit(test.run());
In lines 6 to 10 of this code, we add a startup main.js
code and wait for a while before starting the test.
code coverage check
Good test cases need to consider that the test cases need to cover every branch of the business to ensure that the business is executed correctly. At this time, you can use code coverage check to determine whether the test is complete.
This process is very simple, just add the --cov parameter when testing:
1fibjs --cov test
After the test is completed, a log file fibjs-xxxx.lcov will be generated in the current directory. At this time, the log needs to be analyzed and a report generated:
1fibjs --cov-process fibjs-xxxx.lcov out
A set of analysis reports can be generated in the out directory. Enter the directory to check, and you can see the following page:
You can see that main.js
the code coverage has reached 100%, which means that the test completely covers the business logic. Click main.js
further to see a more detailed report.