简介: 高单测覆盖率不能防止改变引发,小的改变引发就可能带来大的线上问题。
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…
本文为阿里云原创内容,未经容许不得转载。
发表回复