mcpField
T
The Standard Testing

The Standard Testing

github.com/hassanhabib测试与质量2073 次安装13 周前更新
代码仓库

关于 The Standard Testing

The Standard Testing 是面向采用 The Standard 构建的软件的测试技能。它规定 TDD、验证、异常、服务、控制器和 UI 测试实践,并提供测试顺序与约定。

主要功能

  1. 01规定先失败的 TDD 步骤
  2. 02使验证测试对齐存储约束
  3. 03明确服务测试职责
  4. 04涵盖控制器与端点测试
  5. 05提供 UI 组件测试指引
  6. 06规定测试结构与命名约定

适用场景

  1. 01规划服务例程的新测试
  2. 02核对基础层验证与存储约束
  3. 03测试异常映射和依赖调用
  4. 04组织控制器及 UI 组件测试

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/hassanhabib/the-standard-skills --skill the-standard-testing

安装后在 Claude Code 中输入/the-standard-testing确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

manifest.json
contracts/
contracts.json
examples/bad/
example_bad_test.cs
examples/good/
example_validation_test.cs
example_foundation_test.cs
rules/
rules.json
rules.md
templates/
service_test_template.cs
test_class_root_template.cs
templates/controllers/acceptance/
controller_acceptance_test_class_root_template.cs
controller_acceptance_test_template.cs
templates/controllers/unit/
controller_unit_test_class_root_template.cs
controller_unit_test_template.cs
templates/foundations/
foundation_service_test_template.cs
foundation_test_class_root_template.cs
templates/processings/
processing_service_test_template.cs
processing_test_class_root_template.cs
validations/
anti-patterns.md
checklist.md

详细介绍

The Standard 测试

此技能的用途

此技能规定如何测试、验证和证明 The Standard。 其涵盖测试驱动开发、验证策略、异常映射、单元测试结构、控制器测试和 UI 组件测试。

明确的覆盖范围

此技能明确涵盖:

  • Services 章节中的基础服务实现及验证/测试模式
  • 结构、逻辑、外部和依赖项验证测试
  • 异常映射和类别测试
  • 处理服务的测试职责
  • 编排服务的调用顺序测试
  • 聚合服务的测试限制
  • REST 控制器单元测试和验收测试
  • 基础组件、核心组件和页面的 UI 组件测试
  • 所提供的实现规范中关于单元测试、部分测试组织、约定、AAA 和测试顺序的章节
  • 与编写测试和验证实现相关的 TDD FAIL/PASS 规范

使用时机

编写、审查、扩展、修复或安排测试顺序时,请使用此技能。 在决定优先测试什么、如何在测试中映射异常,或如何证明符合 The Standard 的流程时,请使用此技能。

核心测试准则

  1. 遵循 TDD。
  2. 先编写失败的测试。
  3. 确认测试确实失败。
  4. 编写通过测试所需的最少实现。
  5. 确认所有相关测试套件均通过。
  6. 在不改变行为的前提下重构。
  7. 重复以上步骤。

验证测试规则

验证的事实来源
  1. 验证规则必须从所有权威来源推导:

    • 基础服务业务规则
    • 存储层配置(StorageBroker.[Entity].Configurations.cs)
    • 使用方式所隐含的领域预期
  2. 存储配置代表最低强制约束:

    • 必填与可选
    • 最大长度
    • 最小长度(如果已配置)
    • 适用时的精度/比例/格式
  3. 基础服务代表强制执行边界:

    • 所有可能导致持久化失败的约束,必须在到达存储层之前验证
    • 在可以确定地避免数据库异常时,验证必须阻止此类异常
验证一致性规则
  1. 基础验证必须不弱于存储约束。

  2. 以下情况允许(强化规则):

    • 存储层:可选 → 基础层:必填
    • 存储层:可选 → 基础层:受限(最小/最大长度)
    • 存储层:最大长度 → 基础层:更小的最大长度
  3. 以下情况不允许(规则弱化或缺失):

    • 存储层:必填 → 基础层:未按必填进行验证
    • 存储层:最大长度 → 基础层:未进行长度验证
  4. 一致性违规必须视为:

    • 设计缺陷
    • 测试失败条件
    • 审查阻碍
验证职责规则
  1. 不得依赖数据库来执行以下验证:

    • 必填字段验证
    • 长度验证
    • 格式验证
  2. 未事先验证、但可接受由数据库强制执行的约束仅限于:

    • 外键约束
    • 唯一性/重复键约束
    • 并发约束
  3. 凡是能在基础服务中确定地执行的验证,都必须在那里执行

根据存储配置推导验证测试
  1. 存储配置(StorageBroker.[Entity].Configurations.cs)定义的是约束,而非验证行为。

  2. 对于存储配置中定义的每项约束,基础服务中都必须有对应的验证规则:

    • 必填字段
    • 长度约束(最小值/最大值)
    • 适用时的精度/格式约束
  3. 验证测试必须:

    • 仅针对基础服务的验证方法
    • 不得直接测试存储配置行为
    • 证明每项由存储定义的约束都在基础层得到强制执行
  4. 对于每项属性约束,验证测试必须聚焦于违反约束和越界的情况:

    • 无效情况(违反约束)→ 失败

      • 缺少必填字段/字段为 null
      • 值超过最大长度
      • 值低于最小长度(如适用)
    • 越界情况:

      • 刚超过最大值 → 失败
      • 刚低于最小值 → 失败(如适用)
  5. 有效场景(处于可接受范围内)由逻辑测试覆盖,验证测试中不得重复测试。

  6. 存储配置与基础层验证之间缺少一致性,必须视为:

    • 设计缺陷
    • 测试失败条件
    • 评审阻塞项
  7. 自动化可以帮助识别约束(例如,通过 EF 元数据),但:

    • 生成的测试仍必须验证基础服务行为
    • 自动化不得导致测试直接验证数据库层
  8. 所有验证测试必须:

    • 遵循标准命名约定
    • 明确且能清楚表达意图
验证顺序
  1. 首先进行结构验证。
  2. 其次进行逻辑验证。
  3. 第三进行外部验证。
  4. 当外部资源是失败源时,再进行依赖项验证。
熔断式验证
  1. Null 检查和其他硬停止保护必须立即中断。
  2. 如果继续执行会导致无效解引用或无意义的工作,则立即停止。
连续验证
  1. 当多个字段可能各自独立地无效时,先收集所有错误,再抛出异常。
  2. 使用可添加或更新的异常数据。
  3. 使用包含条件和消息的动态规则。
  4. 使用验证收集器例程。
  5. 收集器中存在错误后再抛出异常。
混合式连续验证
  1. 验证父对象后,再验证子属性。
  2. 将嵌套验证拆分为多个层级,以避免意外的 null 引用异常。

基础服务测试规则

  1. 首先测试正常路径。
  2. 然后测试结构验证。
  3. 然后测试逻辑验证。
  4. 然后测试外部验证。
  5. 然后测试依赖项验证。
  6. 然后测试依赖项异常。
  7. 然后测试服务异常。
  8. 始终验证日志记录和 Broker 调用。
  9. 始终验证没有发生不需要的调用。
  10. 始终确保验证行为和异常行为局部且明确。

处理服务测试规则

  1. 测试高阶逻辑,而非原始 Broker 细节。
  2. 仅验证处理服务实际使用的内容。
  3. 测试转换器。
    • 示例:对象 → bool 或对象 → 计数。
  4. 测试组合。
    • 示例:检索 + 添加、检索 + 修改、确保存在、upsert。
  5. 测试处理服务对基础服务异常的映射。

编排服务测试规则

  1. 测试多实体流程组合。
  2. 存在合约映射/分支时,测试相应逻辑。
  3. 当流程依赖顺序时,测试调用顺序。
  4. 当输入/输出自然决定顺序时,优先采用自然顺序。
  5. 当顺序并非由自然流程决定时,使用显式顺序验证。
  6. 验证编排层级的异常包装和解包。
  7. 通过依赖项的形态及其产生的行为,间接测试规范化结果。

聚合服务测试规则

  1. 不要测试聚合服务中的依赖调用顺序。
  2. 不要对聚合服务使用 mock 序列式顺序断言。
  3. 仅测试基本结构验证和暴露层面的聚合行为。
  4. 聚合服务可能会多次调用或直接透传;应测试契约和暴露抽象,而不是编排逻辑。

控制器和协议测试规则

  1. 控制器需要针对映射逻辑编写单元测试。
  2. 对成功代码映射进行单元测试。
  3. 对验证/依赖/服务错误映射进行单元测试。
  4. 对安全性,即授权/身份验证失败映射进行单元测试。
  5. 对每个端点进行验收测试。
  6. 验收测试后清理测试数据。
  7. 运行验收测试时,模拟不属于该微服务的外部资源。
  8. 除单元测试和验收测试外,也可以进行集成测试和端到端测试。

UI 组件测试规则

基础组件
  1. 将基础组件视为轻量封装。
  2. 必要时测试其暴露的 API 和封装行为。
  3. 不要在基础组件中放入业务逻辑。
核心组件
  1. 核心组件采用测试驱动。
  2. 测试元素。
    • 存在性
    • 属性
    • 操作
  3. 可以通过赋值属性、按 ID 搜索或常规搜索来测试存在性。
  4. 当样式属于组件契约的一部分时,测试样式。
  5. 测试会修改状态、创建组件或触发服务调用的操作。
  6. 核心组件应且只能与一个视图服务集成。
页面/容器
  1. 页面是更简单的路由容器。
  2. 通常不需要单元测试。
  3. 不应包含业务逻辑。

所提供实现配置文件中的单元测试约定

  1. 在测试中镜像分部类拆分方式。
  2. 在根测试文件中使用设置方法/辅助方法。
  3. 将测试拆分到逻辑、验证和异常文件中。
  4. 使用 GWT:Given / When / Then。
  5. 模拟所有依赖项。
  6. 使用易读的断言。
  7. 使用深度克隆来保护预期对象的标识。
  8. 默认使用随机数据。
  9. 验证确切的依赖调用。
  10. 以 VerifyNoOtherCalls 结束。
  11. 使用明确且以场景为导向的命名。

基础服务添加例程的精确测试实现顺序

在实现配置文件中实现 Add{Entity}Async 例程时,请遵循以下顺序:

  1. ShouldAdd{Entity}Async
  2. ShouldThrowValidationExceptionOnAddIf{Entity}IsNullAndLogItAsync
  3. ShouldThrowValidationExceptionOnAddIf{Entity}IsInvalidAndLogItAsync
  4. ShouldThrowDependencyValidationExceptionOnAddIfBadRequestErrorOccursAndLogItAsync
  5. ShouldThrowDependencyValidationExceptionOnAddIfConflictErrorOccursAndLogItAsync
  6. ShouldThrowCriticalDependencyExceptionOnAddIfUnauthorizedErrorOccursAndLogItAsync
  7. ShouldThrowCriticalDependencyExceptionOnAddIfForbiddenErrorOccursAndLogItAsync
  8. ShouldThrowCriticalDependencyExceptionOnAddIfNotFoundErrorOccursAndLogItAsync
  9. ShouldThrowCriticalDependencyExceptionOnAddIfUrlNotFoundErrorOccursAndLogItAsync
  10. ShouldThrowDependencyExceptionOnAddIfInternalServerErrorOccursAndLogItAsync
  11. ShouldThrowDependencyExceptionOnAddIfServiceUnavailableErrorOccursAndLogItAsync
  12. ShouldThrowCriticalDependencyExceptionOnAddIfHttpRequestErrorOccursAndLogItAsync
  13. ShouldThrowServiceExceptionOnAddIfServiceErrorOccursAndLogItAsync

对于基于存储的服务,请替换为相应的存储异常,例如重复键、DbUpdate 和 SQL 异常。

所提供实现配置文件中的测试和异常/本地化补充说明

8. 单元测试

单元测试遵循 The Standard 的分部类 + 三轴方法。

8.1 测试类结构

每个实体的测试都采用与服务相同的分部类拆分方式:

分部文件测试
{Entity}ServiceTests.cs初始化、模拟对象、辅助方法(CreateRandom{Entity} 等)
{Entity}ServiceTests.Logic.{Method}.cs正常路径/成功场景测试
{Entity}ServiceTests.Validations.{Method}.cs验证失败测试
{Entity}ServiceTests.Exceptions.{Method}.cs依赖项和服务异常测试
8.2 约定
约定详情
模拟Moq — Mock<IStorageBroker>、Mock<IModernApiBroker>、Mock<ILoggingBroker>
断言FluentAssertions — Should().BeEquivalentTo()
深度克隆DeepCloner — 隔离输入/预期/实际对象
数据生成Tynamix.ObjectFiller — 使用自定义属性设置的 Filler<{Entity}>
异常比较通过 SameExceptionAs 表达式辅助方法调用 Xeption.SameExceptionAs()
测试命名Should{Action}Async / ShouldThrow{Exception}On{Action}If{Condition}AndLogItAsync
验证调用每项测试都会验证 Broker 调用(Times.Once / Times.Never),并以 VerifyNoOtherCalls() 结束
测试框架xUnit — 单个用例使用 [Fact],参数化用例使用 [Theory] [InlineData]
8.3 测试模式 — GWT(给定/当/则)
// given  — build input, configure mocks, construct expected exception
// when   — invoke the service method
// then   — assert result / exception, verify broker interactions
8.4 测试实现顺序

测试必须按以下严格顺序编写并提交。此顺序可确保每个类别都在前一个类别的基础上构建:

  1. 正常路径 — ShouldAdd{Entity}Async
  2. 结构验证 — 检查实体是否为 null(ShouldThrowValidationExceptionOnAddIf{Entity}IsNullAndLogItAsync)
  3. 逻辑验证 — 使用 [Theory] [InlineData] 进行属性级检查(ShouldThrowValidationExceptionOnAddIf{Entity}IsInvalidAndLogItAsync)
  4. 外部依赖验证异常 — BadRequest → Conflict
  5. 外部关键依赖异常 — Unauthorized → Forbidden → NotFound → UrlNotFound
  6. 外部非关键依赖异常 — InternalServerError → ServiceUnavailable
  7. 传输层异常 — HttpRequestException
  8. 兜底服务异常 — Exception

对于基于存储的服务,第 4–7 步替换为相应的 SQL/EF 异常 (DuplicateKeyException、DbUpdateException、SqlException)。

规则 — 提交前验证测试: 每个 FAIL 提交都必须确保测试实际运行并失败。每个 PASS 提交都必须确保所有测试运行并通过。切勿在未验证测试运行器报告了真实失败的情况下提交 FAIL。详情请参阅第 12.1.3 节 — 提交。


9. 关键库

包用途
Xeption增强型异常,支持数据聚合
EFxceptionsEF Core 封装,用于抛出有意义的异常
RESTFulSense用于外部 API 代理的 HTTP 客户端封装
Moq单元测试模拟框架
FluentAssertions可读性更强的断言语法
DeepCloner基于值的测试对象深度克隆
Tynamix.ObjectFiller随机测试数据生成
xunit单元测试框架

异常处理原则

0. 范围

这些规则适用于所有服务层的异常设计、本地化、分类、传播和测试。


1. 本地化(强制)
  1. 外部(非本地)异常必须在边界处(Foundation)进行本地化。
  2. 原生异常(SQL、HTTP、SDK)不得跨越服务边界。
  3. 本地化必须将原生异常转换为特定于领域的异常。

数据保留(强制)

  1. 必须将外部异常中的所有相关数据复制到本地异常:

    • Data 字典
    • 约束/验证元数据
    • 标识符/键
  2. 本地化后的异常必须携带这些数据,以确保:

    • 直接内部异常在分类后包含完整的验证详情。

2. 分类
  1. 所有异常必须归为以下类别之一:

    • Validation
    • DependencyValidation
    • Dependency
    • Service
  2. 分类决定上游处理方式和 exposer 映射。


3. 传播(解包/重新封装)

每个服务层必须:

  1. 捕获下游异常
  2. 解包分类异常
  3. 保留本地异常
  4. 重新封装为自身的分类异常

这可以防止泄露较低层的关注点,并强制遵守层级契约。


4. 保留内部异常(强制)
  1. 必须始终将原始本地异常保留为内部异常。
  2. 任何层都不得丢弃或替换本地异常。

这可以确保:

  • 可追溯性
  • 正确的 exposer 映射(例如 HTTP Conflict/FailedDependency)
  • 保留验证数据

5. 层级职责
Foundation
  1. 本地化外部异常
  2. 填充本地异常数据
  3. 分类为 Validation / DependencyValidation / Dependency / Service
Processing
  1. 只能处理已分类的异常
  2. 不得依赖 Foundation 异常类型
  3. 必须重新封装为 Processing 层级的异常
Orchestration
  1. 必须处理来自所有依赖项的异常
  2. 必须将每种类型统一为单个分类异常
  3. 必须解包并保留内部异常

6. 全捕获(强制)
  1. 每个服务都必须实现:
    • catch (Exception)
  2. 必须映射为 ServiceException

这可以防止泄露未知故障。


7. 日志记录
  1. 每一层都必须在重新抛出前记录日志
  2. 只能记录分类后的异常

8. 测试
Orchestration 异常测试
  1. 应使用 [Theory]
  2. 必须在单个测试中覆盖多种依赖异常类型
  3. 必须避免重复

9. 设计意图

这些规则旨在确保:

  1. 与外部系统完全隔离
  2. 稳定的层级契约
  3. 简化的 exposer 逻辑
  4. 在本地异常层级完整呈现验证信息

异常处理交叉引用(执行)

验证测试对齐
  1. 所有验证测试 MUST 遵循异常处理原则:

    • MUST 验证本地化(不暴露原生异常)
    • MUST 验证本地异常发生时的数据保留情况
    • 验证异常 MUST 在内部异常中包含完整的错误详情
    • 从处理服务层开始向上,其依赖项中的验证异常和依赖验证异常会重新包装为 [Entity][Layer]DependencyValidationExceptions
    • 从处理服务层开始向上,其依赖项中的依赖异常和服务异常会重新包装为 [Entity][Layer]DependencyExceptions
  2. 验证测试 MUST 断言:

    • 正确的本地异常类型
    • 正确的分类异常类型
    • 内部异常包含验证数据(Data 字典已填充)

基础异常测试(强制要求)
  1. 测试 MUST 验证本地化:

    • 原生异常 → 本地异常 → 分类异常
  2. 测试 MUST 验证:

    • 外部异常数据已复制到本地异常
    • 本地异常作为内部异常保留
  3. 测试 MUST NOT 允许:

    • 原生异常泄漏
    • Data 字典传播缺失

处理异常测试(强制要求)
  1. 测试 MUST 断言:

    • 重新包装为处理层异常
    • 内部异常保留
  2. 测试 SHOULD:

    • 使用 [Theory] 在一个测试中测试同一类型的多个依赖验证异常
    • 使用 [Theory] 在一个测试中测试同一类型的多个依赖异常
    • 在单个测试方法中测试多个用例,避免重复

编排异常测试(强制要求)
  1. 测试 MUST 断言:

    • 重新包装为编排层异常
    • 内部异常保留(本地异常)
    • 在编排层替换分类异常
  2. 测试 SHOULD:

    • 使用 [Theory] 在一个测试中测试同一类型的多个依赖验证异常
    • 使用 [Theory] 在一个测试中测试同一类型的多个依赖异常
    • 在单个测试方法中测试多个用例,避免重复

全捕获强制要求
  1. 测试 MUST 验证:
    • 未知异常映射为 ServiceException
    • 任何服务层都不会逸出原始 Exception

日志记录强制要求
  1. 测试 MUST 验证:
    • 抛出异常前已进行日志记录
    • 记录的异常是分类异常

设计完整性规则
  1. 任何违反异常处理原则的情况 MUST 视为:
    • 设计缺陷
    • 测试失败
    • 评审阻塞项

评论

支持 Markdown