笔者负责的npm包是 ICBU信天翁低代码平台渲染引擎,160+应用 600+页面基于该引擎开发,内网日npm下载 1K+。经过不懈努力(CV),终于把单测提到了95%。
然而,虽然在覆盖率上获得了一些数据的改变,但作为开发者,想要的并不是数据上的完美,而是它真的完美(没BUG)。作为一个高频引用的底层库,改动一行代码都可以影响到用户意想不到的bug。
高单测覆盖率不能避免改动引发,小的改动引发就可能带来大的线上问题。
issue=单测
每一个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}成功`);
// 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}`);
}
});
});
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。
单测=文档
原子类单测可以极大程度保证代码稳定性,组件类可以描述开发者期望的用法。
单测即文档
除此之外,issue的Milestone代表对应npm版本:
// changelog
1. 【FEAT】列表过滤提供类似表单的校验模式
2. 【FEAT】model内置属性应该不可枚举
3. 【FEAT】期望提供ref注解,方便平台侧做区分
4. 【Bug】watch 在正则的模式下,调用 silent validate 会导致 autoValidate 失效
issue的最好归宿就是cover by test。钉钉 -> issue -> npm changelog 相互对应,做到每个单测可溯源。
笔者负责的框架已经推行了一年,再回顾一下。值得思考的是,重头设计一次架构,是否能完美的解决现在的这些issue。
这些issue和单测都是走过的脚印,现在我们已经积累单测170+, 其中60+ issue原子类单测。不能保证0BUG。但可预见的是让用户放心用,不会有改动引发。单测是质量的守门神,帮助框架做好用户预期,一步步更稳健的前行。
写单测最好的时间是项目开始前,其次是现在。
“阿里灵杰”问天引擎电商搜索算法大赛
点击阅读原文查看详情。