用途
该技能用于在 .NET 项目中引入基于 Verify 的快照测试(Snapshot Testing)。快照测试会捕获输出,并与人工审核过的基线进行比对:首次运行生成 .received. 文件(包含实际输出),开发者审核后批准生成 .verified. 文件,后续运行将输出与 .verified. 文件比对,检测到变化时测试失败,并通过 diff 工具展示差异供审核。这种方式既能捕获非预期变化,又允许通过显式批准放行有意变更。
适用场景包括:验证渲染输出(HTML 邮件、报告、生成代码);审批公共 API 表面以检测破坏性变更;测试 HTTP 响应体与响应头;校验序列化输出;捕获复杂对象中的非预期变化。
主要能力
- 对象快照验证:直接对 DTO 等对象调用 Verify,生成可读的 .verified.txt。
- 字符串/HTML 验证:通过 extension 参数指定扩展名(如 html),生成可在浏览器中查看的 .verified.html。
- 邮件模板测试:渲染 MJML 等模板后快照,捕获 CSS/布局回归、模板变量损坏等问题。
- API 表面审批:通过反射导出公共类型与成员,或使用 PublicApiGenerator 包生成完整 API 表面快照,任何变更都需显式批准。
- HTTP 响应测试:将状态码、自定义响应头与响应体组合为一个匿名对象进行验证。
- 动态值擦除(Scrub):使用 ScrubMember 或全局 VerifierSettings 擦除时间戳、GUID 等每次运行都变化的值,替换为占位符(如 Guid_1、DateTime_1)。
- 文件组织与版本控制:推荐 Snapshots 目录结构,.gitignore 忽略 .received.,.gitattributes 将 .verified. 标记为 linguist-generated。
- CI/CD 集成:在 CI 环境中禁用 diff 工具启动并改用 DiffPlex 输出,GitHub Actions 中设置 CI=true 并在失败时上传快照产物。
使用方式
安装包:
dotnet add package Verify.Xunit
或其他测试框架:
dotnet add package Verify.NUnit dotnet add package Verify.MSTest
配置 ModuleInitializer.cs:
using System.Runtime.CompilerServices;
public static class ModuleInitializer { [ModuleInitializer] public static void Init() { VerifyBase.UseProjectRelativeDirectory("Snapshots"); // DiffTools.UseOrder(DiffTool.Rider, DiffTool.VisualStudioCode); } }
基础用法示例:
[Fact] public Task VerifyUserDto() { var user = new UserDto( Id: "user-123", Name: "John Doe", Email: "john@example.com", CreatedAt: new DateTime(2025, 1, 15));
return Verify(user);
}
HTML 验证:
await Verify(html, extension: "html");
API 表面审批(使用 PublicApiGenerator):
dotnet add package PublicApiGenerator dotnet add package Verify.Xunit
[Fact] public Task ApproveApi() { var api = typeof(MyPublicClass).Assembly.GeneratePublicApi(); return Verify(api); }
动态值擦除:
return Verify(order) .ScrubMember("Id") .ScrubMember("CreatedAt");
全局擦除配置:
VerifierSettings.ScrubMembersWithType<DateTime>(); VerifierSettings.ScrubMembersWithType<DateTimeOffset>(); VerifierSettings.ScrubMembersWithType<Guid>(); VerifierSettings.AddScrubber(s => Regex.Replace(s, @"token=[a-zA-Z0-9]+", "token=SCRUBBED"));
CI 配置:
if (Environment.GetEnvironmentVariable("CI") == "true") { VerifyDiffPlex.UseDiffPlex(OutputType.Minimal); DiffRunner.Disabled = true; }
适用场景
- 渲染 HTML/邮件:是,可捕获视觉回归。
- API 表面:是,防止意外破坏。
- 序列化输出:是,校验传输格式。
- 复杂对象图:是,比手动断言更简单。
- 简单值检查:否,应使用常规断言。
- 业务逻辑:否,应使用显式断言。
- 性能测试:否,应使用基准测试。
限制与注意事项
- 不要对未擦除的随机/动态数据做快照,否则每次运行都会失败。
- 不要提交 .received 文件,只提交 .verified 文件。
- 不要用于简单断言(如计数),应使用 Assert.Equal。
- 测试名称会成为文件名,应使用描述性命名。
- 非文本内容需通过 extension 参数指定扩展名。
相关资源
- Verify GitHub: https://github.com/VerifyTests/Verify
- Verify.Xunit: https://github.com/VerifyTests/Verify.Xunit
- ApiApprover: https://github.com/JakeGinnivan/ApiApprover
- DiffPlex Integration: https://github.com/VerifyTests/Verify.DiffPlex