CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Vibe Coding 实战入门/课时/测试
RawBlame
课时目录12 节

Vibe Coding 实战入门

  1. 01Vibe Coding 是什么
  2. 02先规划再编码
  3. 03Cursor 与 Windsurf
  4. 04Claude Code 与 Codex
  5. 05Copilot 与 Gemini
  6. 06v0 与 Lovable
  7. 07技术栈选择
  8. 08提示与上下文
  9. 09调试
  10. 10版本控制
  11. 11测试
  12. 12安全

测试

让 AI 写可测代码。

25 分钟

测试

这一课你将能做到

  1. 让 AI 生成覆盖正常、边界、异常三类场景的单元测试
  2. 识别并修正 AI 生成测试的典型缺陷(测试通过但没验证、mock 过度、边界遗漏)
  3. 建立「AI 生成测试 + 人工审查」的纪律,确保测试真的有用

为什么要学

AI 是生成单元测试的神器——写测试的痛点(繁琐、重复、覆盖不全)恰好是 AI 的强项。但 AI 生成的测试有个隐蔽的坑:它们经常「看起来都对,实际上什么都没测」。

人话:AI 写的测试就像 AI 写的代码一样,需要审查。一个不验证结果的测试(assertNotNull(result) 就完事),一个 mock 掉所有依赖的测试(测的是 mock 不是代码),一个只测 happy path 的测试(边界全靠运气)——这些测试的存在感比没有还危险,因为它们给你虚假的安全感。

真实项目中,测试是 AI 生成代码的最后一道质量门。没有测试的 AI 代码,就像没有验收报告的施工——看起来盖好了,住进去才知道哪面墙是歪的。

先建立图像

AI 生成测试的质量光谱:
┌─────────────────────────────────────────┐
│ 好测试:                                 │
│   ✓ 验证行为(不只验证返回值不为 null)   │
│   ✓ 覆盖边界(空、null、极值、并发)      │
│   ✓ 验证异常(抛了正确的异常类型和信息)   │
│   ✓ 真实依赖或最小 mock                  │
├─────────────────────────────────────────┤
│ 坏测试(AI 常犯的):                     │
│   ✗ assertNotNull 就完事                 │
│   ✗ mock 掉所有依赖,测的是 mock          │
│   ✗ 只测正常路径,不测边界和异常          │
│   ✗ 测试逻辑复制被测代码的 bug            │
└─────────────────────────────────────────┘

跟着做

步骤 1:让 AI 生成三类场景的测试

给一个真实的服务方法,让 AI 生成完整测试:

// 被测方法
public Article publish(Long articleId, Long operatorId) {
    Article article = articleMapper.selectById(articleId);
    if (article == null) {
        throw new BusinessException("文章不存在");
    }
    if (!article.getAuthorId().equals(operatorId)) {
        throw new BusinessException("只能发布自己的文章");
    }
    if ("PUBLISHED".equals(article.getStatus())) {
        throw new BusinessException("文章已发布,不能重复发布");
    }
    article.setStatus("PUBLISHED");
    article.setPublishedAt(LocalDateTime.now());
    articleMapper.updateById(article);
    return article;
}

提示词:

为上面的 publish 方法生成单元测试,要求:
1. 覆盖正常场景:作者发布自己的草稿文章
2. 覆盖边界场景:文章不存在、非作者操作、已发布状态
3. 覆盖异常场景:数据库操作异常
4. 每个测试验证:返回值、数据库状态变更、异常类型和消息
5. 用 JUnit 5 + Mockito,不要 mock 掉被测方法本身

步骤 2:审查 AI 生成的测试

AI 通常会给出一版「看起来不错」的测试。你要按清单审查:

清单 1:是否验证了行为?

// 差:只验证不抛异常
@Test
void publish_success() {
    assertDoesNotThrow(() -> articleService.publish(1L, 1L));
}

// 好:验证状态变更和返回值
@Test
void publish_success() {
    Article result = articleService.publish(1L, 1L);
    assertEquals("PUBLISHED", result.getStatus());
    assertNotNull(result.getPublishedAt());
    verify(articleMapper).updateById(argThat(a -> 
        "PUBLISHED".equals(a.getStatus())
    ));
}

清单 2:是否覆盖了边界?

// AI 常漏掉的边界:
- articleId 为 null
- operatorId 为 null
- article 的 status 为 null(不是 "DRAFT" 也不是 "PUBLISHED")
- publishedAt 时区问题(如果涉及时区)

清单 3:mock 是否过度?

// 差:mock 掉了所有东西,测试失去了意义
when(articleMapper.selectById(any())).thenReturn(mock(Article.class));
when(articleMapper.updateById(any())).thenReturn(1);
// 这个测试能过,但数据库约束、SQL 错误、字段映射问题都测不到

// 好:用 H2 内存数据库或 Testcontainers,测真实 SQL
@SpringBootTest
@AutoConfigureTestDatabase(replace = Replace.ANY)
class ArticleServiceIntegrationTest {
    // 真实 Mapper + 真实数据库(H2),测的是真实行为
}

步骤 3:让 AI 补全遗漏的边界

审查后把遗漏点反馈给 AI:

补充以下场景的测试:
1. articleId 为 null 时抛 IllegalArgumentException
2. article 的 status 为 null 时的处理逻辑
3. 并发场景:两个线程同时发布同一篇文章,应该只有一个成功

步骤 4:建立「AI 测试纪律」

写进团队规则文件:

## AI 生成测试的纪律
- 每个测试必须验证行为,不允许只 assertNotNull
- 边界场景(null、空、极值)必须人工检查是否覆盖
- 数据库操作优先用 H2/Testcontainers 集成测试,mock 只用于外部服务
- 并发场景必须测(如果业务涉及共享状态)
- AI 生成的测试和 AI 生成的代码走相同的 Code Review 流程

讲清楚要点

  1. AI 生成测试的价值在「覆盖」,风险在「虚假覆盖」:AI 能快速生成 20 个测试方法,但其中 15 个可能什么都没验证。审查的核心是「这个测试失败时,能发现什么 bug」。
  2. mock 的粒度决定测试的价值:mock 掉所有依赖的单元测试,测的是「mock 的行为」不是「代码的行为」。数据库操作用 H2/Testcontainers 集成测试,mock 只留给外部 HTTP 服务。
  3. 边界和异常是 AI 的盲区:AI 倾向于生成 happy path 测试。null、空、极值、并发、时区——这些需要人工列出清单,让 AI 补。
  4. 测试代码也是代码,需要 Review:AI 生成的测试可能复制被测代码的 bug(比如被测代码算错了,测试也断言错误的结果)。测试的断言要基于「业务应该是什么样」,不是「代码现在是什么样」。
  5. 测试是 AI 生成代码的验收标准:没有测试的 AI 代码,你无法确认它「做了什么」和「应该做什么」是否一致。

你可能会懵的地方

  • AI 生成的测试覆盖率很高,是不是就够了? 覆盖率是必要不充分条件。100% 行覆盖率但全是 assertNotNull 的测试,价值为零。关注「分支覆盖率」和「断言质量」,不只是行覆盖率。

  • AI 能生成集成测试和端到端测试吗? 能,但质量参差不齐。集成测试(@SpringBootTest + H2)AI 生成得不错;端到端测试(Playwright/Selenium)涉及页面交互,AI 生成的选择器和等待逻辑常需要手工修正。

  • 测试代码也要原子提交吗? 要。测试和被测代码分开提交,或至少分开 commit。这样 Review 时可以单独看「测试是否覆盖了需求」。

  • AI 生成的测试总是通过,但代码明明有 bug,怎么回事? 典型场景:被测代码有 bug,AI 生成的测试「学习」了这个 bug,断言了错误的结果。对策:测试的断言必须基于需求文档或业务规则,不是基于代码实现。

  • 老项目没测试,能让 AI 补吗? 能,但要分层补:先补「核心业务流程」的集成测试(给钱相关的、给用户数据的),再补单元测试。补测试时让 AI 先「读代码总结行为」,再生成测试,而不是直接生成。

错法对照

错法问题正解
assertNotNull(result) 就完事什么都没验证验证状态变更、返回值、异常消息
mock 掉所有依赖测的是 mock 不是代码数据库用 H2 集成测试,mock 只给外部服务
只测 happy path边界全靠运气人工列出边界清单,让 AI 补
测试断言复制代码 bug测试通过但逻辑错误断言基于业务需求,不是代码实现
覆盖率 90% 就觉得够了虚假安全感看分支覆盖率和断言质量,不看行覆盖率

卡点急救

  1. AI 生成的测试跑不过:把失败信息贴给 AI,让它分析是「测试写错了」还是「代码有 bug」。两者都有可能,AI 倾向于修测试让测试通过,你要判断哪个是对的。
  2. 老代码没法测(静态方法、私有方法、硬编码依赖):让 AI 先做「可测试性重构」(提取接口、依赖注入),再生成测试。直接给不可测试的代码生成测试,AI 会用反射等黑魔法,测试很脆弱。
  3. 并发场景的测试 AI 写不好:并发测试本身就很难写(线程调度、时序不确定)。让 AI 生成「基于 CountDownLatch/CyclicBarrier 的确定性并发测试」,或直接用现成框架(如 jcstress)。

面试常问

  • AI 生成测试的最大风险是什么?怎么控制? 高分回答:最大风险是「虚假覆盖」——测试通过但没验证行为。控制方法:纪律上要求每个测试必须验证状态变更或异常;流程上 AI 生成的测试走和代码相同的 Review;技术上用变异测试(mutation testing)工具(如 PIT)验证测试真的能发现 bug。

  • 如何为遗留系统补测试? 分层补:先补核心业务流程的集成测试(保障不回归),再补单元测试(提升覆盖率)。补测试前先做可测试性重构(依赖注入、提取接口)。AI 可以加速「读代码总结行为」和「生成测试骨架」两个环节。

  • TDD 在 AI 时代还有意义吗? 有,而且更重要。TDD 的核心价值是「先想清楚应该什么样,再写代码」——这恰好是 AI 协作的核心能力(描述需求+验收结果)。AI 时代可以「AI 辅助 TDD」:你写测试(或让 AI 生成测试骨架),AI 实现代码,你验收测试是否通过。

自测三问

  1. AI 生成测试的三个典型缺陷是什么?
  2. 为什么「mock 掉所有依赖」的测试价值很低?
  3. 为遗留系统补测试的分层策略是什么?

小结一句话

AI 是生成测试的神器,但「测试通过」不等于「质量过关」——审查断言质量、覆盖边界场景、用集成测试替代过度 mock,测试才真正是你的安全网。

延伸

  • JUnit 5 官方文档
  • Testcontainers 官方文档
  • PIT 变异测试
  • 下一课:安全——AI 生成代码的安全审查清单。
加载本节练习…
← 上一课版本控制下一课 →安全