Guide Development Guide

A good life starts with testing

A programmer who does not write automatic test cases is not a good test engineer. We encourage all projects to establish complete automated test cases at the very beginning. With the development of the project, the initial investment will be rewarded hundreds of times.

Let's continue the example from the previous section and take a look at how to use fibjs to write test cases.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
const 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 10
var test = require('test'); test.setup(); describe('hello, test', () => { it('a empty test', () => { }); }); test.run();

After saving it as test.js , execute fibjs test.js on the command line, 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 test server

Because we need to test the http server, we need to start the server first. The test case will send a request to the server, and then test the result of the request to determine whether the server meets the requirements:

1 2 3 4 5 6 7 8 9 10 11 12 13 14
var 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 judge whether the server logic is normal by verifying whether the result of http.get is the result we expect. According to this example, we can quickly complete a set of tests, and we also optimized the 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
var 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();

Group management of use cases

Let's add the bonjour test. 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 content of hello and bonjour are the same, we optimized the code again and tested the two sets of services with the same set of codes:

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
var 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 it is also easy to skip and test a group of use cases individually to speed up development and testing. The following are the results of 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. According to the above example, I believe you can quickly write out 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 directly complete the test. We can use the following code to achieve:

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 43
var 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~10 of this code, we added a section of code to start main.js , and waited 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, code coverage checks can be used to determine whether the test is complete.

This process is very simple, just add the --cov parameter when testing:

1
fibjs --cov test

After the test is completed, a log file of fibjs-xxxx.lcov will be generated in the current directory. At this time, it is necessary to analyze the log and generate a report:

1
fibjs --cov-process fibjs-xxxx.lcov out

Then you can generate a set of analysis reports in the out directory. Enter the catalog to view, you can see the following page:cov As you can see, the code coverage of main.js reaches 100%, indicating that the test completely covers the business logic. Click main.js further to see a more detailed report.

👉 [ Find the performance killer ]