简介:高单测覆盖率不能防止改变引发,小的改变引发就可能带来大的线上问题。
image.png
作者 | 范喆 (六瓶)
起源 | 阿里开发者公众号
高单测等于高质量?
笔者负责的 npm 包是 ICBU 信天翁低代码平台渲染引擎,160+ 利用 600+ 页面基于该引擎开发,内网日 npm 下载 1K+。通过不懈努力(CV),终于把单测提到了 95%。
然而,尽管在覆盖率上取得了一些数据的扭转,但作为开发者,想要的并不是数据上的完满,而是它真的完满(没 BUG)。作为一个高频援用的底层库,改变一行代码都能够影响到用户意想不到的 bug。
高单测覆盖率不能防止改变引发,小的改变引发就可能带来大的线上问题。
写好单测
issue= 单测
每一个 issue 都有它命中注定的一个单测
在咱们的我的项目中,用 issue 来治理用户需要。用户每发现一个问题都能够到咱们指定仓库中去提 issue,新增的 issue 触发机器人在钉钉群里艾特对应批改人,修复后机器人告诉创建人。
image.png
在软件工程中,对单元测试的形容是“针对每一个单元的测试,以确保每个模块能失常工作为指标”。
在咱们行覆盖率和分支覆盖率都很高的状况下,还须要有新的机制保障模块更稳固。除去那些框架还没摸索到的业务场景,怎么样保障当初用户的肯定没有问题?
于是有了 issue 即单测。
在当初的 issue 运作机制下,保障每一个单侧都有对应的 issue。在仓库中新增了脚本 tnpm run create-issue。
// package.json
“scripts”: {
"create-issue": "node ./script/issue_dev/createIssueTem.js",
}
// createIssueTem.js
/**
- 疾速创立 issue 示例
*/
const path = require(‘path’);
const execSync = require(‘child_process’).execSync;
const args = process.argv.slice(2);
const issueID = args[0];
if (!issueID) {
console.error(‘ 须要输出 issue id 能力运行 ’);
process.exit();
}
const demoTarget = path.resolve(__dirname, ../../demo/issue_${issueID}
);
const demoSrc = path.resolve(__dirname, ../template/demo/base.md
);
const testTarget = path.resolve(__dirname, ../../test/issues-cov/${issueID}
);
const testSrc = path.resolve(__dirname, ../template/test/*
);
const specTarget = path.resolve(__dirname, ../../test/issues-cov/${issueID}/app.spec.tsx
);
execSync(mkdir ${demoTarget}
);
execSync(cp ${demoSrc} ${demoTarget}/
);
execSync(sed -i '''s/issueID/${issueID}/g' ${demoTarget}/base.md
);
execSync(mkdir ${testTarget}
);
execSync(cp ${testSrc} ${testTarget}
);
execSync(sed -i '''s/issueID/${issueID}/g' ${specTarget}
);
console.log(创立 ${issueID}胜利
);
在公布前把对应的 demo 做删除
// prebuild
// 构建前删除 issue 的 demo
const fs = require(‘fs’);
const path = require(‘path’);
const ENV = process.env.BUILD_ENV == ‘cloud’;
function removeDir(dir) {
let files = fs.readdirSync(dir);
for (var i = 0; i < files.length; i++) {
let newPath = path.join(dir, files[i]);
let stat = fs.statSync(newPath);
if (stat.isDirectory()) {
// 如果是文件夹就递归上来
removeDir(newPath);
} else {
// 删除文件
fs.unlinkSync(newPath);
}
}
fs.rmdirSync(dir); // 如果文件夹是空的,就将本人删除掉
}
fs.readdir(‘./demo’, (err, path) => {
if (err) {
console.log(err);
}
path.forEach((pathItem) => {
if (pathItem.includes('issue') && ENV) {removeDir(`./demo/${pathItem}`);
console.log(` 删除 ${pathItem}`);
}
});
});
当咱们运行 tnpm run create-issue 123456,帮咱们创立对应 issue 123456 的单测 +demo,复用同一个 template 内容,能够在浏览器端看到 demo,也能够在 vs code 中间接编写单测内容。
image.png
在 demo 中,能够间接点击 gitlab 链接跳转到对应 issue。
image.png
这里拿一个简略的 issue 做演示:
image.png
对应的原子单测
describe(‘116193’, () => {
it(‘should work’, async () => {
const wrapper = mount(<App />);
await sleep(10);
wrapper.mount();
expect(Object.keys(A)).toMatchSnapshot();
expect(A.hasApplied).toBeDefined();
return wrapper.unmount();
});
});
单测非常简单,尽管只有两句 expect,但这两句是只为这个 issue 存在,强行 cp。
issue 惟一单测笼罩,保障 0 改变引发。
在业界一些优良的开源框架也是有同样的 issue 即单测的案例,比方 mobx。
image.png
单测 = 文档
原子类单测能够极大水平保障代码稳定性,组件类能够形容开发者冀望的用法。
单测即文档
image.png
闭环积淀反哺
除此之外,issue 的 Milestone 代表对应 npm 版本:
// changelog
1.24.0
- 【FEAT】列表过滤提供相似表单的校验模式 #115827(cover by test)
- 【FEAT】model 内置属性应该不可枚举 #116193(cover by test)
- 【FEAT】冀望提供 ref 注解,不便平台侧做辨别 #116364
- 【Bug】watch 在正则的模式下,调用 silent validate 会导致 autoValidate 生效 #116242(cover by test)
issue 的最好归宿就是 cover by test。钉钉 -> issue -> npm changelog 互相对应,做到每个单测可溯源。
image.png
笔者负责的框架曾经推广了一年,再回顾一下。值得思考的是,重头设计一次架构,是否能完满的解决当初的这些 issue。
这些 issue 和单测都是走过的足迹,当初咱们曾经积攒单测 170+,其中 60+ issue 原子类单测。不能保障 0BUG。但可预感的是让用户释怀用,不会有改变引发。单测是品质的守门神,帮忙框架做好用户预期,一步步更持重的前行。
最初
写单测最好的工夫是我的项目开始前,其次是当初。
“阿里灵杰”问天引擎电商搜索算法大赛
原文链接:http://click.aliyun.com/m/100…
本文为阿里云原创内容,未经容许不得转载。