tdd

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

/tdd -- Red-Green-Refactor for .NET

/tdd -- .NET 的红-绿-重构工作流

What

概述

Guides a strict test-driven development cycle for .NET features. Instead of writing implementation first and bolting on tests after, this command flips the order: write a failing test that defines the desired behavior, implement the minimum code to make it pass, then refactor with confidence.
Every cycle uses the .NET testing stack:
  • xUnit v3 -- Test framework with
    [Fact]
    and
    [Theory]
  • WebApplicationFactory -- Integration tests against the real HTTP pipeline
  • Testcontainers -- Real databases (PostgreSQL, SQL Server) in tests
  • Verify -- Snapshot testing for complex response structures
  • FakeTimeProvider -- Deterministic time in tests
指导.NET功能的严格测试驱动开发循环。不同于先编写实现代码再附加测试,此命令颠倒顺序:先编写一个定义预期行为的失败测试,再编写最少代码使其通过,最后自信地进行重构。
每个循环使用.NET测试栈:
  • xUnit v3 -- 支持
    [Fact]
    [Theory]
    的测试框架
  • WebApplicationFactory -- 针对真实HTTP管道的集成测试
  • Testcontainers -- 在测试中使用真实数据库(PostgreSQL、SQL Server)
  • Verify -- 针对复杂响应结构的快照测试
  • FakeTimeProvider -- 测试中的确定性时间

When

适用场景

  • User says "TDD", "test-driven", "let's TDD this", "write the test first"
  • Building a new feature with clear acceptance criteria
  • Fixing a bug (write a test that reproduces the bug first, then fix)
  • Adding behavior to an existing feature (test the new behavior first)
  • Any time the user wants proof that code works before it ships
Skip TDD for: Trivial config changes, scaffolding without logic, documentation.
  • 用户提及"TDD"、"test-driven"、"let's TDD this"、"write the test first"时
  • 构建具有明确验收标准的新功能时
  • 修复bug时(先编写重现bug的测试,再修复)
  • 为现有功能添加行为时(先测试新行为)
  • 任何用户希望在代码交付前证明其有效的场景
跳过TDD的场景: 琐碎的配置更改、无逻辑的脚手架搭建、文档编写。

How

实施流程

Cycle: Red -> Green -> Refactor

循环:红 → 绿 → 重构

Each feature goes through one or more TDD cycles. A cycle covers one discrete behavior.
每个功能需经历一个或多个TDD循环。一个循环对应一个独立的行为。

Step 1: Red -- Write the Failing Test

步骤1:红阶段 -- 编写失败的测试

Write a test that describes the desired behavior. The test MUST fail because the implementation does not exist yet.
csharp
[Fact]
public async Task CreateOrder_WithValidItems_Returns201WithOrderId()
{
    // Arrange
    var client = _factory.CreateClient();
    var request = new CreateOrderRequest([
        new OrderItemRequest("SKU-001", 2, 29.99m)
    ]);

    // Act
    var response = await client.PostAsJsonAsync("/api/orders", request);

    // Assert — plain xUnit Assert (FluentAssertions v8+ requires a commercial license)
    Assert.Equal(HttpStatusCode.Created, response.StatusCode);
    var result = await response.Content.ReadFromJsonAsync<CreateOrderResponse>();
    Assert.NotNull(result);
    Assert.NotEqual(Guid.Empty, result.OrderId);
}
Run the test and confirm it fails:
bash
dotnet test --filter "CreateOrder_WithValidItems_Returns201WithOrderId"
If the test passes without implementation, the test is not testing what you think. Rewrite it.
编写描述预期行为的测试。由于实现代码尚未存在,测试必须失败。
csharp
[Fact]
public async Task CreateOrder_WithValidItems_Returns201WithOrderId()
{
    // Arrange
    var client = _factory.CreateClient();
    var request = new CreateOrderRequest([
        new OrderItemRequest("SKU-001", 2, 29.99m)
    ]);

    // Act
    var response = await client.PostAsJsonAsync("/api/orders", request);

    // Assert — 原生xUnit断言(FluentAssertions v8+需要商业许可)
    Assert.Equal(HttpStatusCode.Created, response.StatusCode);
    var result = await response.Content.ReadFromJsonAsync<CreateOrderResponse>();
    Assert.NotNull(result);
    Assert.NotEqual(Guid.Empty, result.OrderId);
}
运行测试并确认失败:
bash
dotnet test --filter "CreateOrder_WithValidItems_Returns201WithOrderId"
如果未编写实现代码测试就通过,说明测试未覆盖预期内容,请重写测试。

Step 2: Green -- Minimal Implementation

步骤2:绿阶段 -- 最小化实现

Write the minimum code to make the test pass. Do not add features, optimizations, or edge case handling. The goal is a green test, nothing more.
  • Create the endpoint, handler, request/response types, and EF config as needed
  • Use the simplest logic that satisfies the test assertion
  • Do not refactor yet -- ugly passing code is fine at this stage
Run the test and confirm it passes:
bash
dotnet test --filter "CreateOrder_WithValidItems_Returns201WithOrderId"
编写最少代码使测试通过。不要添加额外功能、优化或边缘情况处理。目标仅为让测试通过。
  • 根据需要创建端点、处理器、请求/响应类型和EF配置
  • 使用满足测试断言的最简单逻辑
  • 此时无需重构——丑陋但能通过的代码是可接受的
运行测试并确认通过:
bash
dotnet test --filter "CreateOrder_WithValidItems_Returns201WithOrderId"

Step 3: Refactor -- Clean Up with Confidence

步骤3:重构阶段 -- 自信地优化代码

Now that the test is green, refactor freely:
  • Extract methods, rename variables, improve structure
  • Apply modern C# patterns (primary constructors, records, collection expressions)
  • Add validation, error handling, and edge cases (with new tests for each)
  • Run the full test suite after each refactor step to catch regressions
bash
dotnet test
If any test goes red during refactoring, undo the last change and try a smaller step.
测试通过后,可自由重构:
  • 提取方法、重命名变量、优化结构
  • 应用现代C#模式(主构造函数、记录、集合表达式)
  • 添加验证、错误处理和边缘情况(为每种情况编写新测试)
  • 每次重构后运行完整测试套件,避免回归问题
bash
dotnet test
如果重构期间任何测试失败,撤销最后一次更改,尝试更小的重构步骤。

Multi-Cycle Features

多循环功能

Most features require multiple TDD cycles. Plan the cycles upfront:
Feature: Order Management

Cycle 1: Create order with valid items -> 201
Cycle 2: Create order with empty items -> 400 validation error
Cycle 3: Create order with invalid SKU -> 400 with specific error
Cycle 4: Get order by ID -> 200 with full order details
Cycle 5: Get order that does not exist -> 404
Each cycle adds one behavior. Never combine multiple behaviors in a single cycle.
大多数功能需要多个TDD循环,请提前规划:
Feature: Order Management

Cycle 1: 创建包含有效商品的订单 -> 返回201状态码
Cycle 2: 创建空商品订单 -> 返回400验证错误
Cycle 3: 创建包含无效SKU的订单 -> 返回400特定错误
Cycle 4: 通过ID查询订单 -> 返回200及完整订单详情
Cycle 5: 查询不存在的订单 -> 返回404状态码
每个循环添加一个行为。切勿在单个循环中合并多个行为。

Test Infrastructure Setup

测试基础设施搭建

If the project lacks test infrastructure, set it up before the first cycle:
  1. Create test project with xUnit v3 and required packages
  2. Configure
    WebApplicationFactory
    with Testcontainers for the real database
  3. Add a shared fixture to avoid spinning up containers per test class
  4. Verify the infrastructure with a simple health-check test
如果项目缺少测试基础设施,请在第一个循环前完成设置:
  1. 创建包含xUnit v3和所需包的测试项目
  2. 配置
    WebApplicationFactory
    ,使用Testcontainers连接真实数据库
  3. 添加共享夹具,避免为每个测试类启动容器
  4. 使用简单的健康检查测试验证基础设施

Example

示例

User: /tdd Let's TDD a product search endpoint

Claude: I'll plan the TDD cycles for product search:

Cycle 1: Search with matching term returns matching products
Cycle 2: Search with no matches returns empty list
Cycle 3: Search with pagination returns correct page
Cycle 4: Search with filters narrows results

Starting Cycle 1: Red phase
Writing a failing integration test for basic product search...

[writes test, runs it, confirms failure]

Cycle 1: Green phase
Implementing the minimum to make the search test pass...

[implements, runs test, confirms pass]

Cycle 1: Refactor phase
The implementation works but the query could use a projection
instead of loading full entities. Refactoring...

[refactors, runs full suite, all green]

Cycle 1 complete. Moving to Cycle 2...
用户: /tdd 我们来对产品搜索端点进行TDD开发

Claude: 我将为产品搜索规划TDD循环:

Cycle 1: 使用匹配关键词搜索返回匹配产品
Cycle 2: 无匹配关键词搜索返回空列表
Cycle 3: 带分页的搜索返回正确页面
Cycle 4: 带筛选条件的搜索缩小结果范围

开始Cycle 1:红阶段
编写一个失败的基础产品搜索集成测试...

[编写测试,运行并确认失败]

Cycle 1:绿阶段
编写最少代码使搜索测试通过...

[实现代码,运行测试并确认通过]

Cycle 1:重构阶段
实现代码可行,但查询可以使用投影而非加载完整实体。开始重构...

[重构代码,运行完整测试套件,全部通过]

Cycle 1完成。进入Cycle 2...

Related

相关命令

  • /verify
    -- Run full verification after completing all TDD cycles
  • /scaffold
    -- Generate initial feature structure that tests will drive
  • /verify
    -- 完成所有TDD循环后运行完整验证
  • /scaffold
    -- 生成测试将驱动的初始功能结构