使用nyc/istanbul统计代码覆盖率遇阻,需适配Nightwatch及Jenkins CI
我之前也碰到过类似的困扰——Nightwatch作为端到端测试工具,业务代码是在浏览器里运行的,而nyc默认只能追踪Node.js环境下的代码执行(也就是你的测试代码),这就是为什么你看到测试代码覆盖率100%,但完全没统计到业务代码的原因。而Jest单元测试能正常工作,是因为Jest本身要么在Node环境跑代码,要么用jsdom模拟浏览器,而且和nyc有原生的集成,能直接把覆盖率数据传给nyc。
下面是一步步解决这个问题的方案,最后也会提到Jenkins的集成方式:
1. 给业务代码做插桩(Instrumentation)
要统计浏览器里的业务代码覆盖率,首先得给业务代码插入统计代码,这样浏览器才能记录代码的执行情况。常用的方式有两种:
方式一:用Babel插件在构建时插桩(推荐,适合用Webpack/Rollup的项目)
如果你的项目用Babel构建,安装babel-plugin-istanbul:
npm install --save-dev babel-plugin-istanbul
然后在你的Babel配置文件(比如.babelrc或babel.config.js)里,只在测试环境启用这个插件:
{ "env": { "test": { "plugins": ["istanbul"] } } }
这样构建测试环境的业务代码时,就会自动插入覆盖率统计的代码,浏览器运行时会把数据存在window.__coverage__对象里。
方式二:用nyc手动插桩代码
如果不用Babel,可以直接用nyc的instrument命令处理业务代码目录:
nyc instrument src/ src-instrumented/
之后要确保Nightwatch测试加载的是src-instrumented/目录下的插桩后的代码。
2. 在Nightwatch中收集浏览器的覆盖率数据
接下来需要在测试结束后,从浏览器里提取覆盖率数据,并保存到nyc能识别的目录(默认是.nyc_output/)里。
修改你的Nightwatch配置文件(比如nightwatch.conf.js),添加全局钩子:
module.exports = { // 其他配置... globals: { after(testDone) { // 从浏览器中获取覆盖率数据 browser.executeScript(() => window.__coverage__, (result) => { if (result.value) { const fs = require('fs'); const path = require('path'); const outputDir = '.nyc_output'; // 确保输出目录存在 if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir, { recursive: true }); } // 生成唯一的文件名,避免覆盖 const filename = path.join(outputDir, `coverage-${Date.now()}.json`); // 写入覆盖率数据 fs.writeFileSync(filename, JSON.stringify(result.value)); } testDone(); }); } } };
这个钩子会在每个测试用例结束后,提取浏览器里的__coverage__数据,写入到.nyc_output目录下的JSON文件中。
3. 用nyc生成覆盖率报告
完成测试并收集到数据后,运行nyc的report命令来生成报告:
nyc report --reporter=html --reporter=text
你也可以指定其他格式,比如cobertura(适合Jenkins集成):
nyc report --reporter=cobertura --reporter=html
完整的命令流程大概是:
# 1. 构建插桩后的业务代码(如果用Babel的话,直接跑构建命令即可) npm run build:test # 2. 运行Nightwatch测试,同时收集覆盖率数据 nightwatch # 3. 生成覆盖率报告 nyc report
4. Jenkins CI集成
要在Jenkins里展示覆盖率报告,需要做以下几步:
- 在Jenkins服务器上确保安装了Node.js和项目依赖(可以用
npm install步骤)。 - 在构建步骤中执行上述的测试+覆盖率报告生成命令。
- 安装Jenkins的Cobertura Plugin,然后在构建后步骤中添加“Publish Cobertura Coverage Report”,指定报告路径为
./coverage/cobertura-coverage.xml(这是nyc report --reporter=cobertura生成的文件)。 - 配置完成后,Jenkins会在构建页面显示覆盖率的统计和趋势图。
注意事项
- 不要在生产环境的代码中保留插桩代码,确保只在测试环境启用
babel-plugin-istanbul或者使用单独的测试构建流程。 - 如果你的业务代码有压缩混淆,插桩后的代码要避免被压缩,否则覆盖率数据会不准确。
- 确保Nightwatch能正确访问到插桩后的业务代码(比如本地测试服务器加载的是插桩后的文件)。
内容的提问来源于stack exchange,提问作者xploreraj

