agent-skills中的测试驱动开发:如何让AI代理写出可靠代码

【免费下载链接】agent-skills Production-grade engineering skills for AI coding agents. 【免费下载链接】agent-skills 项目地址: https://gitcode.com/GitHub_Trending/agentskill/agent-skills

在AI驱动的开发环境中,确保代码质量和可靠性变得前所未有的重要。agent-skills项目中的测试驱动开发(TDD) 技能为AI代理提供了一套系统化方法,通过先写测试再编码的方式,确保产出的代码既可靠又易于维护。本文将详细介绍如何利用agent-skills中的测试驱动开发技能,让AI代理遵循专业工程实践,构建高质量软件。

什么是测试驱动开发(TDD)?

测试驱动开发是一种软件开发方法论,其核心原则是在编写实际功能代码前先编写失败的测试。这种"测试先行"的方式迫使开发者在动手编码前先明确需求和预期行为,从而减少后期修改成本并提高代码质量。

agent-skills中的test-driven-development技能将这一方法论系统化,为AI代理提供了清晰的工作流程和最佳实践。当需要实现新功能、修复bug或修改现有行为时,TDD技能能指导AI代理构建可靠的解决方案。

TDD的核心工作流程:红-绿-重构循环

agent-skills的TDD技能基于经典的"红-绿-重构"循环,这三个阶段形成了一个持续改进的开发闭环:

1. 红(RED):编写失败的测试

首先编写一个必然失败的测试。这个测试定义了期望的功能或行为,但由于实现代码尚未编写,测试应该明确地失败。

// RED: 这个测试会失败,因为createTask函数还不存在
describe('TaskService', () => {
  it('创建带有标题和默认状态的任务', async () => {
    const task = await taskService.createTask({ title: '购买 groceries' });
    
    expect(task.id).toBeDefined();
    expect(task.title).toBe('购买 groceries');
    expect(task.status).toBe('pending');
    expect(task.createdAt).toBeInstanceOf(Date);
  });
});

一个立即通过的测试是没有价值的,它无法证明代码的正确性。只有先看到测试失败,才能确认当测试通过时,确实是因为功能被正确实现。

2. 绿(GREEN):编写最小化代码

在测试失败后,编写刚好足够的代码使测试通过。这一阶段不追求代码的完美,只关注让测试通过。

// GREEN: 最小化实现
export async function createTask(input: { title: string }): Promise<Task> {
  const task = {
    id: generateId(),
    title: input.title,
    status: 'pending' as const,
    createdAt: new Date(),
  };
  await db.tasks.insert(task);
  return task;
}

这个阶段的目标是快速获得反馈,验证测试的有效性,并确认基本功能可以工作。

3. 重构(REFACTOR):优化代码

测试通过后,进入重构阶段。在保持测试通过的前提下,改进代码质量:

  • 提取重复逻辑
  • 优化命名
  • 消除代码异味
  • 提高性能

每次重构后都要运行测试,确保功能没有被破坏。这个循环不断重复,逐步构建出高质量的代码。

修复bug的"证明它"模式(Prove-It Pattern)

agent-skills的TDD技能特别强调了修复bug时的"证明它"模式,这是一种确保bug被彻底修复且不会复发的有效方法:

  1. 收到bug报告
  2. 编写能复现bug的测试(此时测试应该失败)
  3. 实现修复
  4. 验证测试通过
  5. 运行完整测试套件确保没有回归
// 步骤1: 编写复现测试(应该失败)
it('完成任务时设置completedAt时间戳', async () => {
  const task = await taskService.createTask({ title: '测试' });
  const completed = await taskService.completeTask(task.id);
  
  expect(completed.status).toBe('completed');
  expect(completed.completedAt).toBeInstanceOf(Date);  // 这会失败 → 确认bug存在
});

// 步骤2: 修复bug
export async function completeTask(id: string): Promise<Task> {
  return db.tasks.update(id, {
    status: 'completed',
    completedAt: new Date(),  // 之前缺少这行
  });
}

// 步骤3: 测试通过 → bug修复,防止回归

这种方法确保每个bug修复都有对应的测试保护,避免未来的修改再次引入相同问题。

测试金字塔:平衡测试策略

agent-skills的TDD技能倡导遵循测试金字塔原则,合理分配测试资源:

          ╱╲
         ╱  ╲         端到端测试 (~5%)
        ╱    ╲        完整用户流程,真实浏览器环境
       ╱──────╲
      ╱        ╲      集成测试 (~15%)
     ╱          ╲     组件交互,API边界测试
    ╱────────────╲
   ╱              ╲   单元测试 (~80%)
  ╱                ╲  纯逻辑,隔离测试,毫秒级执行
 ╱──────────────────╲
  • 单元测试(约80%):测试独立功能单元,快速且隔离
  • 集成测试(约15%):测试组件间交互和API边界
  • 端到端测试(约5%):测试关键用户流程,使用真实浏览器环境

遵循"碧昂斯规则":如果你喜欢它,就应该为它写个测试。基础设施变更、重构和迁移不负责捕获bug,测试才是。如果一个变更破坏了代码而你没有对应的测试,那是你的责任。

编写高质量测试的关键原则

agent-skills的TDD技能提供了编写有效测试的详细指南,以下是核心原则:

测试状态而非交互

断言操作的结果,而非内部方法调用。验证方法调用序列的测试在重构时容易断裂,即使行为未变。

// 好:测试函数做什么(基于状态)
it('按创建日期降序返回任务', async () => {
  const tasks = await listTasks({ sortBy: 'createdAt', sortOrder: 'desc' });
  expect(tasks[0].createdAt.getTime())
    .toBeGreaterThan(tasks[1].createdAt.getTime());
});

// 差:测试函数内部如何工作(基于交互)
it('调用db.query时使用ORDER BY created_at DESC', async () => {
  await listTasks({ sortBy: 'createdAt', sortOrder: 'desc' });
  expect(db.query).toHaveBeenCalledWith(
    expect.stringContaining('ORDER BY created_at DESC')
  );
});

DAMP优于DRY

在生产代码中,DRY(不重复自己)通常是对的。但在测试中,DAMP(描述性和有意义的短语) 更好。测试应该读起来像规格说明,每个测试都应该讲述完整的故事,不需要读者追踪共享辅助函数。

优先使用真实实现而非模拟

使用最简单的测试替身完成工作。测试使用真实代码越多,提供的信心越足:

优先顺序(从最优先到最不优先):
1. 真实实现 → 最高信心,捕获真实bug
2. 伪实现 → 依赖的内存版本(如假数据库)
3. 存根 → 返回预设数据,无行为
4. 模拟(交互) → 验证方法调用 — 谨慎使用

只有当真实实现太慢、不确定或有无法控制的副作用(外部API、发送邮件)时才使用模拟。过度模拟会导致测试通过但生产环境失败。

采用Arrange-Act-Assert模式

it('截止日期过后标记任务为逾期', () => {
  // Arrange: 设置测试场景
  const task = createTask({
    title: '测试',
    deadline: new Date('2025-01-01'),
  });

  // Act: 执行被测试的操作
  const result = checkOverdue(task, new Date('2025-01-02'));

  // Assert: 验证结果
  expect(result.isOverdue).toBe(true);
});

每个概念一个断言

// 好:每个测试验证一个行为
it('拒绝空标题', () => { ... });
it('从标题中修剪空白', () => { ... });
it('强制执行标题最大长度', () => { ... });

// 差:所有内容放在一个测试中
it('正确验证标题', () => {
  expect(() => createTask({ title: '' })).toThrow();
  expect(createTask({ title: '  hello  ' }).title).toBe('hello');
  expect(() => createTask({ title: 'a'.repeat(256) })).toThrow();
});

描述性的测试命名

// 好:读起来像规格说明
describe('TaskService.completeTask', () => {
  it('设置状态为已完成并记录时间戳', ...);
  it('对不存在的任务抛出NotFoundError', ...);
  it('是幂等的 — 完成已完成的任务是无操作', ...);
  it('向任务负责人发送通知', ...);
});

// 差:模糊的名称
describe('TaskService', () => {
  it('works', ...);
  it('处理错误', ...);
  it('test 3', ...);
});

常见的测试反模式及避免方法

agent-skills的TDD技能详细列出了需要避免的测试反模式:

反模式 问题 解决方案
测试实现细节 重构时即使行为未变,测试也会断裂 测试输入和输出,而非内部结构
不稳定测试(时序、顺序依赖) 削弱对测试套件的信任 使用确定性断言,隔离测试状态
测试框架代码 浪费时间测试第三方行为 只测试你的代码
滥用快照 大型快照无人审查,任何更改都会断裂 谨慎使用快照并审查每个更改
无测试隔离 单独运行通过但一起运行失败 每个测试设置和清理自己的状态
模拟一切 测试通过但生产环境失败 优先使用真实实现 > 伪实现 > 存根 > 模拟。只在真实依赖慢或不确定时模拟

何时在agent-skills中使用子代理进行测试

对于复杂的bug修复,agent-skills建议生成子代理来编写复现测试:

主代理:"生成一个子代理来编写复现此bug的测试:
[bug描述]。使用当前代码时测试应该失败。"

子代理:编写复现测试

主代理:验证测试失败,然后实现修复,
然后验证测试通过。

这种分离确保测试是在不知道修复方案的情况下编写的,使其更加健壮。

开始使用agent-skills中的TDD技能

要在项目中使用agent-skills的测试驱动开发能力,请参考以下资源:

开始使用TDD的最佳方式是:

  1. 克隆agent-skills仓库:git clone https://gitcode.com/gh_mirrors/agentskill/agent-skills
  2. 阅读docs/getting-started.md中的设置说明
  3. 在给AI代理的指令中明确引用TDD技能:"遵循test-driven-development流程进行此更改"

克服常见的TDD阻力

采用TDD时,开发者常提出一些理由反对,agent-skills的TDD技能对这些理由进行了有力反驳:

理由 现实
"我会在代码工作后写测试" 你不会。事后写的测试测试的是实现,而不是行为。
"这太简单了,不需要测试" 简单代码会变得复杂。测试记录了预期行为。
"测试拖慢了我" 测试现在拖慢你,但以后每次更改代码时都会加速你。
"我手动测试过了" 手动测试不会持久。明天的更改可能会破坏它,而你无从知晓。
"代码自解释" 测试才是规格说明。它们记录代码应该做什么,而不是它做了什么。
"这只是个原型" 原型会变成生产代码。从第一天开始写测试可以防止"测试债务"危机。

结论:用TDD构建更可靠的AI生成代码

agent-skills中的测试驱动开发技能为AI代理提供了一套系统化方法,确保生成的代码既可靠又易于维护。通过"红-绿-重构"循环、"证明它"bug修复模式和测试金字塔策略,AI代理能够遵循专业工程实践,构建高质量软件。

无论是实现新功能、修复bug还是优化现有代码,TDD都能帮助AI代理产出更健壮、更可维护的代码。开始使用test-driven-development技能,体验测试先行开发带来的好处!

【免费下载链接】agent-skills Production-grade engineering skills for AI coding agents. 【免费下载链接】agent-skills 项目地址: https://gitcode.com/GitHub_Trending/agentskill/agent-skills

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐