品质保证:发布覆盖率测试报告
代码覆盖率才是评价一个项目品质的标准。在挑选一个项目的时候,有经验的使用者都会根据代码覆盖率来确定代码的可靠性。
虽然自动化测试工具可以自动验证代码的正确性,但是如果只有部分代码经过了测试,或者只是简单地跑通了代码,也不能说是一个合格的代码。比如组件库只测试一部分的组件,或者每个组件只测试了默认设置。譬如,按钮中某个属性或者某几个属性间的排列组合并没有得到测试,这样的测试还不能保证组件库的功能完全正确。
那么如何来客观评价这个测试的完备程度呢?答案就是代码覆盖率。
覆盖率概念
代码覆盖率(Code coverage)是软件测试中的一种度量指标,描述测试过程中(运行时)被执行的源代码占全部源代码的比例。
覆盖率指标种类
只是简单地做到行级覆盖还远远不够,可以看看下面的例子。
function getName(a, b) {
if(a && b) {
return 'Jane'
}else {
return 'Tony'
}
}
以上代码只需要两个 Case,就可以将所有语句都跑一遍:
Case01: a = true ; b = true; 期待:Jane
Case02: a =false ; b= true; 期待:Tony
但是,显然这样测试甚至不能确定代码中 b 是否参与条件判断。比如下面代码可能也会出现相同的结果。
function getName(a, b) {
if(a) {
return 'Jane'
}else {
return 'Tony'
}
}
所以假设覆盖率只有简单的代码行覆盖还远远不够。
在软件工程理论中会把覆盖率分为:
语句覆盖(statement coverage)
判定覆盖(decision coverage)
条件覆盖(condition coverage)
条件判定组合覆盖(condition decision coverage)
路径覆盖(path coverage)
多条件覆盖(multi-condition coverage)
修正条件判定覆盖(modified condition / decision coverage)
覆盖深度的提高显然会让代码功能验证更加全面,但是相应的实施成本也会明显提高。
理论的覆盖虽然全面但是实际生产很多指标的指导价值并不是很大。在实际生产中会将它进行简化。
在Javascript语言中,代码覆盖率通常会分为四级覆盖。
Function coverage 函数覆盖 - 每个函数是否被执行;
Line coverage 行覆盖 -- 每行是否被执行;
Statement coverage 语句覆盖 - 每个语句是否被执行;
Branch coverage 分支覆盖 - 每个 if 节点是否都被执行。
这是结合了函数式语言的特点和指标的实用程度的经验之谈,也是 JavaScript 世界比较受认可的标准。
用户故事(UserStory)
为组件库发布覆盖率报告,使测试覆盖率可视化。
任务分解(Task)
生成覆盖率报告;
将覆盖率报告任务加入到 CI;
上传覆盖率展示平台 Codecov;
获取覆盖率徽章。
Istanbul 代码覆盖率工具
代码覆盖率需要专用的工具生成。在 JavaScript 程序中的代码覆盖率通常都是通过 Istanbul 生成的。Istanbul 的来历是伊斯坦布尔的地毯,覆盖率报告其实就是用颜色来表示代码的运行情况,好像给代码铺上了地毯。
我们熟悉的 Jest 和组件库使用的 Vitest 测试框架,都是使用的 Istanbul。Istanbul 的实现原理是通过编译期代码插桩方式实现的。有兴趣的同学可以研究一下。咱们这里面只讲如何使用。
生成覆盖率报告
在 Vitest 只需要在命令行中添加参数 --coverage 就可以生成覆盖率报告了。
package.json
"scripts": {
"coverage": "vitest run --coverage"
},
默认报告形式是一个静态网站。
如果想对报告进行进一步调整,可以在 vite.config.ts 中进行。
test: {
coverage: {
provider: "istanbul", // or 'c8',
reporter: ["text", "json", "html"],
},
},
我调整的两项是:
指定覆盖率引擎 istanbul;
指定输出格式,默认是没有 json 格式的。这个和后面的覆盖率展示有关,务必要加。
公布覆盖率报告
覆盖率报告放在本地只能给自己的单元测试提供依据,更大的用途在于将覆盖率报告公布展示出来,让使用者可以看到。通常会选用覆盖率展示平台,常用的有 Codecov 和 Coveralls。
Codecov 是一个开源的测试结果展示平台,将测试结果可视化。Github 上许多开源项目都使用了 Codecov 来展示单测结果。Codecov 跟 Travis CI 一样都支持 Github 账号登录,同样会同步 Github 中的项目。
还会自动的生成徽章。这个徽章是会根据报告结果动态变化的,属于客观的第三方数据,具有公信力。
首先需要登录 Codecov 网站。
一定要使用 Github 账号进行登录**,**这样它可以直接读取你的 Github 中的项目。
然后是添加访问授权,如果你的项目在你名下的组织下,也需要访问授权。
这时候你就可以在网站上找到所有 Github 中的项目。选择 【Not yet setup 】,选择需要展示覆盖率报告的网站后的【 setup repo】链接,就可以看到安装指南。
它这个安装指南是针对所有语言项目的。这里面我们只需要得到它的上传 Token 就好了。
持续集成自动更新覆盖率报告
覆盖率报告最好能够自动按照最新版本持续更新,而不是自己手动上传。所以这个时候就需要使用 CI 工具来帮忙了。首先需要编写一个 Action。
.github/wokflows/codecov.yml
# .github/workflows/main.yml
# This is a basic workflow to help you get started with Actions
name: Code Coverage
# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
on:
push:
branches: [main]
pull_request:
branches: [main]
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
CodeCov:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- uses: actions/checkout@v2
- uses: pnpm/action-setup@v2.1.0
with:
version: 7.2.1
- name: Install modules
run: pnpm install
- name: Run Test Coverage
run: cd packages/smarty-ui-vite && pnpm coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
directory: packages/smarty-ui-vite/coverage
token: ${{ secrets.CODECOV_TOKEN }}
上传报告环节同样使用现成的 Action 。这里面需要添加 Token,把上面 codecov 安装指南中得到的 Token 放入 Secrets 中。
提交代码就可以自动生成覆盖率报告了。
Codecov Action 会自动识别语言与测试框架的覆盖率报告种类,然后上传相应的数据。这里面要特别说明,对于 Vitest ,是上传的 json 格式的报告,所以需要确定你确实生成了 json 报告。如何生成可以看上文介绍。
添加覆盖率徽章
最后就是富有仪式感的一步。Codecov 网站可以将测试结果生成为徽章。你可以把徽章直接放到 Github 中展示出来。
在项目的【 Settings 】中找到对应的徽章。
复盘
这节课的主要内容是介绍覆盖率概念和发布测试覆盖率报告。
覆盖率报告是项目品质的重要指标,成熟的项目都会把项目展示在显眼的位置,大家通常都会拿代码覆盖率指标评价开源代码的成熟度。当然过高的覆盖率也会带来成本的提高,和拉低项目进步速率。
品质、进度、成本是每一个项目管理中都需要均衡的东西。所以一味追求代码覆盖率也未必是好事。这个大家要客观看待。
最后留一些思考题帮助大家复习,也欢迎在留言区讨论。
分支覆盖和行覆盖间的关系?
如何用 Codecov 完成覆盖率展示 ?
下节课,我们将给大家讲解如何使用 PullRequest,下节课见。