TypeScript 代码测试覆盖率:如何停止猜测,开始测量
\n\n想象一下,您正在组装一个带有许多齿轮的复杂机械。您确信一切安装正确,但一按下“启动”按钮,就传来刺耳的摩擦声,机械卡住了。似曾相识?在 TypeScript 开发的世界里,这些“机械”就是我们的应用程序。而代码测试覆盖率就像一次试组装,它告诉我们哪些零件已经检查过,哪些还听天由命。
\n\n许多开发者对覆盖率指标持怀疑态度:“追求百分比是万恶之源”,“100% 覆盖率并不能保证没有 bug”。这确实是事实。但就像任何工具一样,代码覆盖率可以有益,也可能有害——完全取决于如何使用它。在本文中,我们将探讨如何正确测量 TypeScript 中的覆盖率,有哪些可用工具,以及如何避免让指标成为目的本身。
\n\n什么是代码覆盖率,为什么 TypeScript 也不例外
\n\n代码覆盖率 (code coverage) 是一项指标,显示测试执行期间运行了原始代码的哪一部分。在编译为 JavaScript 的 TypeScript 中,覆盖率测量是在编译后的代码层面进行的,但现代工具能够以原始 TS 代码的形式漂亮地显示结果。
\n\n需要了解的主要覆盖率指标:
\n\n- \n
- 行覆盖率 (Line coverage) — 至少执行过一次的代码行百分比。 \n
- 分支覆盖率 (Branch coverage) — 经过测试的分支(if/else、switch、三元运算符)百分比。 \n
- 函数覆盖率 (Function coverage) — 被调用过的函数/方法百分比。 \n
- 语句覆盖率 (Statement coverage) — 代码中单个指令(语句)的百分比。 \n
对于 TypeScript 项目,分支覆盖率尤为重要,因为强类型并不能防止条件中的逻辑错误。您可以正确定义所有变量的类型,但可能会忘记数组为空而函数期望至少一个元素的情况。
\n\nTypeScript 覆盖率测量工具
\n\n1. Istanbul (nyc) — 覆盖率工具之祖
\n\nIstanbul 是测量 JavaScript 和 TypeScript 代码覆盖率最流行的工具。它可以作为独立工具(通过 nyc 包)运行,也可以作为测试框架的内置模块使用。
要在 TypeScript 项目中开始使用 Istanbul,请安装:
\n\nnpm install --save-dev nyc typescript ts-node\n\n创建 .nycrc 配置文件:
{\n "extends": "@istanbuljs/nyc-config-typescript",\n "all": true,\n "include": ["src/**/*.ts"],\n "exclude": ["src/**/*.test.ts", "src/**/*.spec.ts"],\n "reporter": ["text", "html", "lcov"],\n "check-coverage": true,\n "branches": 80,\n "lines": 85,\n "functions": 85,\n "statements": 85\n}\n\n运行带覆盖率的测试:
\n\nnpx nyc mocha --require ts-node/register src/**/*.test.ts\n\nIstanbul 会在控制台 (text) 和 HTML 页面中生成报告,其中绿色高亮显示已覆盖的代码,红色显示未覆盖的代码。非常直观。
\n\n2. Jest — 一站式解决方案
\n\nJest 是 TypeScript 最流行的测试框架。它已经包含了基于 Istanbul 的内置覆盖率工具。您无需安装任何额外内容。
\n\n在 jest.config.ts 中的基本配置:
import type { Config } from 'jest';\n\nconst config: Config = {\n preset: 'ts-jest',\n testEnvironment: 'node',\n collectCoverage: true,\n coverageDirectory: 'coverage',\n coverageReporters: ['text', 'html', 'lcov'],\n collectCoverageFrom: [\n 'src/**/*.ts',\n '!src/**/*.test.ts',\n '!src/**/*.spec.ts',\n '!src/types/**/*.ts'\n ],\n coverageThresho