JavaScript coverage rate statistics and javascript coverage rate
Main requirements 1. Support for browser & nodejs
Because javascript can be run in both the browser environment and nodejs environment, you need to be able to measure the unit test coverage in both environments.
2. Transparent and seamless
When writing unit test cases, you do not need to write more code to support coverage rate statistics. You can directly calculate the coverage rate without modifying the previous write cases.
Principle
There are few articles about javascript coverage. The figure below is based on reading the Open Source javascript coverage tool istanbul and the coverage plug-in Karma-coverage of the open source test framework karma. The core idea of javascript coverage rate statistics is to inject statistical code into the corresponding position of the source code. After the code is run, the program running path is determined based on the statistical code statistics, and finally the coverage rate statistics report is generated.
1. Conversion (instrument)
- Use the open-source tool Esprima to analyze the source code and generate a syntax tree
- Inject Statistical Code at the corresponding position in the syntax tree, assign values to the corresponding global variables when the program runs to this position, and ensure that the Code Execution Process can be known based on the global variables after execution.
- Use the open-source tool Escodegen to generate the corresponding javascript code based on the injected syntax tree, that is, the converted code (instrumented code)
Note: The advantage of syntax analysis here is that for writing nonstandard code (such as multiple statements in one row), it is still able to well count information such as branch coverage and combination coverage.
2. run)
In this step, you must first load the converted code:
- Nodejs: directly
require
Hook the statement to achieve seamless implementation, which will be detailed later
- Browser environment: You need to pass the converted code to the browser. If it is a test framework with server such as karma, it needs to be transmitted to the browser through socket. After the execution, the execution result containing the coverage information is sent back to the server to generate the test report.
Then execute the unit test, and the statistical information will be mounted to the global variable.this
Below. For the browser environment,this
Yeswindow
For the nodejs environmentthis
Yesglobal
.
3. generate a report)
This step generates reports in specific formats, such as html, lcov, cobertura, and teamcity, based on the coverage information in the global scalar.
Example
//source codefunction abs(num){ if(abs > 0) return num; else return -num;}
//instrumented codevar __cov_iypKC$dWI6uJFmvxThycaA = (Function('return this'))();if (!__cov_iypKC$dWI6uJFmvxThycaA.__coverage__) { __cov_iypKC$dWI6uJFmvxThycaA.__coverage__ = {}; }__cov_iypKC$dWI6uJFmvxThycaA = __cov_iypKC$dWI6uJFmvxThycaA.__coverage__;if (!(__cov_iypKC$dWI6uJFmvxThycaA['/Users/lonfee88/Codes/testframe/coverage-jasmine-istanbul-karma/abs.js'])) { __cov_iypKC$dWI6uJFmvxThycaA['/Users/lonfee88/Codes/testframe/coverage-jasmine-istanbul-karma/abs.js'] = {"path":"/Users/lonfee88/Codes/testframe/coverage-jasmine-istanbul-karma/abs.js","s":{"1":1,"2":0,"3":0,"4":0},"b":{"1":[0,0]},"f":{"1":0},"fnMap":{"1":{"name":"abs","line":1,"loc":{"start":{"line":1,"column":-15},"end":{"line":1,"column":17}}}},"statementMap":{"1":{"start":{"line":1,"column":-15},"end":{"line":6,"column":1}},"2":{"start":{"line":2,"column":1},"end":{"line":5,"column":14}},"3":{"start":{"line":3,"column":2},"end":{"line":3,"column":13}},"4":{"start":{"line":5,"column":2},"end":{"line":5,"column":14}}},"branchMap":{"1":{"line":2,"type":"if","locations":[{"start":{"line":2,"column":1},"end":{"line":2,"column":1}},{"start":{"line":2,"column":1},"end":{"line":2,"column":1}}]}}};}__cov_iypKC$dWI6uJFmvxThycaA = __cov_iypKC$dWI6uJFmvxThycaA['/Users/lonfee88/Codes/testframe/coverage-jasmine-istanbul-karma/abs.js'];function abs(num){__cov_iypKC$dWI6uJFmvxThycaA.f['1']++;__cov_iypKC$dWI6uJFmvxThycaA.s['2']++;if(abs>0){__cov_iypKC$dWI6uJFmvxThycaA.b['1'][0]++;__cov_iypKC$dWI6uJFmvxThycaA.s['3']++;return num;}else{__cov_iypKC$dWI6uJFmvxThycaA.b['1'][1]++;__cov_iypKC$dWI6uJFmvxThycaA.s['4']++;return-num;}}
Node. js integration coverage
The hook can directly and seamlessly load the converted code, and hook the following two statements:
The code to hook require is throughModule._extensions['.js']
Implemented by assigning values:
Function hookRequire (matcher, transformer, options) {options = options | |{}; var fn = transformFn (matcher, transformer, options. verbose), postLoadHook = options. postLoadHook & typeof options. postLoadHook = 'function '? Options. postLoadHook: null; Module. _ extensions ['. js'] = function (module, filename) {var ret = fn (fs. readFileSync (filename, 'utf8'), filename); if (ret. changed) {// load the code after the instrument and run the module. _ compile (ret. code, filename);} else {// load the original code and run originalLoader (module, filename);} if (postLoadHook) {postLoadHook (filename );}};}
Hook makes coverage integration simple, and does not even need to write code. For example, Mocha coverage integration only needs to use the following call method:
istanbul cover _mocha -- -R spec test/spec
Browser integration coverage
Browser integration coverage is a little tricky. Fortunately, istanbul provides APIs:
- Convert the code (call the istanbul Instrumenter Interface)
- Send the instrumented code to the browser (implemented by yourself)
- Send the execution result containing the coverage information back to the server (implemented by yourself)
- Generate a coverage report based on the returned Coverage Information (call the Reporter interface of istanbul)
Program implementation code coverage and path analysis detection, C ++, C #, Java, and JavaScript (any programming language)
If you use source code plug-in, you need to perform lexical and syntax analysis on the input program to create a syntax analysis tree (there are some ready-made tools such as bison, which can be used by anlr ), the language analysis tree is used to obtain the control flow relationship of the program, and then the basic blocks of the program can be analyzed. To obtain the coverage rate and program execution path, insert the basic blocks and use the inserted probes to record their execution.
Function for counting news browsing times using javascript
For the number of views of a news piece, it is better to add a field corresponding to this news piece in the database to count the number of views, initialized to 0
Every time you click a link to the news, xmlHttp is used (I will only do this ..) Asynchronously access the background page and update this field in the background program to make it + = 1. Isn't that enough.