进阶 vitest.dev 2026-10-22 19:00:41 · 20 阅读

第14章 测试筛选:Vitest 聚焦相关测试的实践指南

测试筛选 随着测试套件不断扩张,每次改动都跑全量测试会越来越慢,也会打断思路。如果在修某个模块的 bug,没必要等几百个无关测试跑完。测试筛选能让你聚焦在正在处理的代码上,只跑相关的测试。

Vitest 提供了多种筛选方式:命令行参数、测试文件内部配置、标签。不同场景各有优势。

性能提示 像 -t、--tags-filter、.only 和 .skip 这类筛选器是按测试文件粒度应用的——Vitest 仍然要逐个加载测试文件来确定哪些测试匹配。在项目较大时,即使最终只执行了几个测试,这个开销也会累积。

为避免这种情况,务必搭配文件路径使用筛选器,让 Vitest 只加载你关心的文件: bash vitest utils.test.ts -t "handles empty input"

或者使用 --experimental.preParse 标志,它通过解析而非完整执行测试文件来发现测试名称: bash vitest --experimental.preParse -t "handles empty input"

按文件名筛选 运行部分测试最简单的方法是传入文件名模式作为 CLI 参数。Vitest 只会运行路径包含指定字符串的测试文件: bash vitest basic

这会匹配路径中包含 basic 的任何测试文件: basic.test.ts basic-foo.test.ts basic/foo.test.ts

当你明确知道要处理哪个文件、想跳过其他所有内容时,这种方式非常实用。

按测试名称筛选 有时你关心的测试埋在包含许多其他测试的文件里。-t(或 --testNamePattern)选项按测试名称而非文件名筛选。它接受正则表达式,并匹配完整测试名称——即包裹的 describe 块名称与测试名称通过 ' > ' 连接后的结果(例如 math > adds): bash vitest -t "handles empty input"

你可以将此与文件筛选器组合,进一步缩小范围: bash vitest utils -t "handles empty input"

这仅运行名称匹配 "handles empty input" 且在匹配 utils 的文件内的测试。

按行号筛选 当你在编辑器中查看特定测试时,通常只想运行那一个测试。你可以直接指定行号: bash vitest basic/foo.test.ts:10

Vitest 将运行包含第 10 行的测试。这需要完整文件名(相对或绝对路径): bash vitest basic/foo.test.ts:10 # 正确 vitest ./basic/foo.test.ts:10 # 正确 vitest /users/project/basic/foo.test.ts:10 # 正确 vitest foo:10 # 错误,部分名称无效 vitest ./basic/foo:10 # 错误,缺少文件扩展名

要运行多个特定测试,用空格分隔: bash vitest basic/foo.test.ts:10 basic/foo.test.ts:25 # 正确 vitest basic/foo.test.ts:10-25 # 错误,不支持范围

按标签筛选 在大型项目中,你可能希望将测试分类并按类别运行。标签允许你给测试打标,然后从 CLI 按这些标签筛选: ts test('renders a form', { tags: ['frontend'] }, () => { // ... })

test('calls an external API', { tags: ['backend'] }, () => { // ... }) bash vitest --tags-filter=frontend

这在 CI 管道中特别有用,比如在前端和后端测试分离的不同 job 中运行,或在快速检查期间跳过缓慢的集成测试。

使用 .only 聚焦特定测试 调试失败的测试时,你希望只运行该测试,而不必每次修改 CLI 参数。在测试或套件上添加 .only 可让 Vitest 跳过该文件中的其他所有内容: ts import { describe, expect, it } from 'vitest'

describe.only('suite', () => { it('test', () => { // 此测试会运行,因为套件标记了 .only expect(Math.sqrt(4)).toBe(2) }) })

describe('another suite', () => { it('skipped test', () => { // 此测试不会运行 expect(Math.sqrt(4)).toBe(2) })

it.only('focused test', () => { // 此测试也会运行,因为它标记了 .only expect(Math.sqrt(4)).toBe(2) }) })

你可以在 describe 块和单个测试上使用 .only。只要文件中任何测试或套件标记了 .only,该文件中所有未标记的测试都会被跳过。

注意 提交前记得移除 .only。默认情况下,如果在 CI 中(process.env.CI 已设置)遇到 .only,Vitest 会使整个测试运行失败,防止你在管道中意外跳过测试。此行为由 allowOnly 选项控制。

为了更早捕获 .only,no-focused-tests ESLint 规则(也在 oxlint 中可用)可以在你提交前在编辑器中标记它。

使用 .skip 跳过测试 .only 的反义词是 .skip。用于临时禁用测试或套件而不删除它们。被跳过的测试仍会显示在报告中,以免你遗忘: ts import { describe, expect, it } from 'vitest'

describe.skip('skipped suite', () => { it('test', () => { // 整个套件被跳过 expect(Math.sqrt(4)).toBe(2) }) })

describe('suite', () => { it.skip('skipped test', () => { // 仅此测试被跳过 expect(Math.sqrt(4)).toBe(2) }) })

当测试不稳定或依赖暂时不可用的外部服务时,这非常有用。它让你保留测试作为提醒,同时解除对套件其他部分的阻塞。

使用 .todo 占位测试 规划新功能时,你可能在编写实际实现之前就知道需要哪些测试。.todo 将测试标记为已计划但尚未编写。它作为提醒显示在报告中: ts import { describe, it } from 'vitest'

describe.todo('unimplemented suite')

describe('suite', () => { it.todo('unimplemented test') })

与 .skip 不同,.todo 测试没有测试主体。它纯粹是未来工作的占位符。

评论 (0)