我用AI写测试代码——六套Prompt模板从单元到全链路

一、写测试代码的痛点不是思路,是写法

1.1 问题在哪

测试的"测什么"你很清楚——正常输入、边界值、异常分支。但具体代码怎么写——该用 @Mock 还是 @MockBean,该 when() 完怎么 verify(),Page Object该怎么组织——这些是每次写都重新翻文档的东西。

1.2 我的做法

自从用了 AI 辅助编码,我把这些重复的"写法"抽成了Prompt模板。告诉AI要测什么、用什么框架、覆盖哪些场景——AI生成测试骨架,我补充业务逻辑。

这些Prompt是实际操作中验证过的,覆盖了从后端单元测试到端到端测试的完整链路。

1.3 六套模板总览

序号 模板 覆盖层次 框架
1 后端单元测试 Service/Controller JUnit 5 + Mockito
2 API接口测试 REST接口 Playwright / RestAssured
3 端到端测试 页面操作 Playwright
4 全链路一键测试 全部串起来 Shell脚本

💡 下面逐个展开,每个模板包含:Prompt原文 + 生成代码示例 + 关键约定说明。


二、后端单元测试 —— 每个方法至少三种覆盖

2.1 Prompt模板

为 [模块名/类名] 写 JUnit 单元测试,覆盖:
- 正常输入/边界值/异常输入
- 数据库操作的事务回滚
- null 安全的防御性编程
- 并发/重入安全性(如有)

技术约定:
- 框架: JUnit 5 + Mockito
- 数据库层: MyBatis mapper 用 H2 内存库或 Mock
- Controller: MockMvc 测试 HTTP 层
- Service: Mock 下层依赖,测业务逻辑
- 文件位置: src/test/java/[包路径]/[类名]Test.java
- 运行: mvn test -pl [模块名] -Dtest=[类名]Test

要求每个方法至少覆盖:
- happy path(正常流程)
- null/empty 输入
- 异常分支的错误码/错误类型验证

2.2 生成的测试代码

@ExtendWith(MockitoExtension.class)
class XxxServiceTest {
    @Mock
    private XxxMapper mapper;
    @InjectMocks
    private XxxService service;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    @DisplayName("正常创建返回ID")
    void create_shouldReturnId() {
        when(mapper.insert(any())).thenReturn(1);
        String id = service.create(new XxxDto());
        assertNotNull(id);
    }

    @Test
    @DisplayName("空参数应抛异常")
    void create_nullParam_shouldThrow() {
        assertThrows(IllegalArgumentException.class, () -> service.create(null));
    }
}

2.3 关键约定说明

核心不是生成代码本身——是Prompt约定了覆盖范围。AI可能会遗漏边界值测试,但你在Prompt里写了 null/empty 输入,它就一定会生成对应的测试方法。

下表对比了"有约定"和"没约定"时AI生成的差异:

约定项 不写 写了
null输入测试 大概率遗漏 每个方法都有
异常分支测试 只生成happy path 覆盖IllegalArgumentException等
技术框架 可能用JUnit 4 严格JUnit 5 + Mockito
文件位置 随便放 按Maven标准目录

三、API接口测试 —— 正常、鉴权、异常三块

3.1 Prompt模板

测试 [模块/控制器] 的所有 REST 接口:

正常场景:
- 请求/响应格式正确(状态码、JSON 结构、字段类型)
- 增删改查完整生命周期:创建 → 查询 → 更新 → 删除 → 确认
- 分页参数的正确行为

鉴权场景:
- 有效 token → 200
- 无 token → 401
- 过期/篡改 token → 401
- 无权限 token → 403

异常场景:
- 必填字段缺失 → 400
- 非法数据类型 → 400
- 不存在的资源 ID → 404
- 重复创建 → 409
- 内部异常 → 500(不泄露敏感信息)

技术约定:
- 框架: Playwright API test 或 JUnit + RestAssured
- 鉴权: 先调登录接口获取 token
- 数据清理: 测试后删除测试数据
- 运行: npx playwright test --reporter=list

3.2 三个测试块的覆盖矩阵

API接口测试的核心是三块覆盖缺一不可

测试块 覆盖场景 验证重点
正常场景 CRUD完整生命周期 + 分页 状态码、JSON结构、字段类型
鉴权场景 4种token状态 200/401/403响应码
异常场景 5种错误输入 400/404/409/500响应码

3.3 关键约定说明

这里最核心的是鉴权场景的约定——不告诉AI的话,它只会测正常返回。401/403的测试需要在Prompt里显式要求。

很多团队的API测试只覆盖了"正常场景"这一块,鉴权和异常完全没测。线上出问题往往就是这两块的漏洞。


四、Playwright端到端测试 —— 模拟真实用户操作

4.1 Prompt模板

用 Playwright 对 [功能/页面] 做端到端测试:

测试场景:
1. 正常流程:[用户操作的完整步骤]
2. 边界:空数据 / 最大值 / 特殊字符
3. 异常:网络断开 / token 过期跳登录 / 后端错误时的 UI 提示

断言清单:
- UI 元素可见性、文本内容
- 操作后 API 返回正确
- 表单提交后数据库持久化
- 页面无 console.error
- 加载态和空态的正确展示

技术约定:
- 框架: Playwright (chromium)
- 配置: baseURL, timeout, screenshot='only-on-failure'
- 鉴权: fixture/beforeEach 中登录
- 文件: e2e/{功能名}.spec.ts

4.2 生成的代码骨架

import { test, expect } from '@playwright/test'

test.describe('功能模块', () => {
  test('操作流程', async ({ authedPage: page }) => {
    await page.goto('/path')
    await page.waitForLoadState('networkidle')
    await page.locator('button.action').click()
    await expect(page.locator('.result')).toBeVisible()
  })
})

4.3 E2E测试的断言层级

端到端测试不只是"点按钮看结果",需要在多个层级做断言:

层级 断言内容 示例
UI层 元素可见性、文本内容 expect(locator).toBeVisible()
网络层 API返回正确 expect(response.status()).toBe(200)
数据层 数据库持久化 查库验证数据已写入
体验层 加载态、空态、错误提示 骨架屏显示 → 数据加载完成
质量层 无console.error page.on('console', ...)

五、全链路一键测试Prompt

5.1 Prompt模板

对 [项目名] 执行全链路测试:
1. 后端单元: mvn test -pl [模块名]
2. 前端单元: npx vitest run
3. API 集成: npx playwright test e2e/api-*.spec.ts
4. E2E: npx playwright test e2e/pages-*.spec.ts

要求:
- 全部通过后输出汇总:通过/失败/跳过数量
- 失败项输出:测试名 + 断言差异 + 修复建议

5.2 四层测试的执行顺序

这个Prompt不是为了生成代码——是让AI帮你跑测试并汇总结果。四层测试按依赖关系从底层往上执行:

执行顺序 测试层 命令 失败时说明
1 后端单元 mvn test -pl [模块名] Service/Mapper逻辑错误
2 前端单元 npx vitest run 组件/工具函数错误
3 API集成 npx playwright test e2e/api-*.spec.ts 接口契约或鉴权问题
4 E2E端到端 npx playwright test e2e/pages-*.spec.ts 用户流程走不通

💡 底层测试失败了,上层不用跑——先修Service再测API。

失败了直接告诉你是哪个测试、差了什么、可能怎么修。


六、这些Prompt为什么有效

6.1 通用Prompt vs 约定Prompt的对比

通用的测试Prompt(“帮我写测试”)效果很差,因为AI不知道你的技术栈、不知道你的覆盖标准、不知道你的运行方式。

对比项 “帮我写测试” 约定式Prompt
技术框架 可能用JUnit 4或TestNG 严格JUnit 5 + Mockito
覆盖范围 只有happy path happy path + null + 异常
文件位置 随意 Maven标准目录
能否直接跑 不能,要改import 能,直接mvn test

6.2 四条约定是核心

这些Prompt有效的关键在于把约定写在了前头

  1. 技术栈约定:JUnit 5 还是 JUnit 4、Mockito 还是 MockBean、Playwright 还是 Cypress
  2. 覆盖标准约定:每个方法至少 happy path + null + 异常三种
  3. 文件位置约定:测试文件和源文件的相对路径关系
  4. 运行命令约定mvn test -pl xxx 还是 npx vitest run

这四条约定了,AI生成的代码就是可用的——跑得起来、放在正确的目录、覆盖了应该覆盖的场景。剩下的业务断言逻辑需要人补,但骨架不需要重写了。

6.3 一句话总结Prompt技巧

好的Prompt不是万能咒语,是把不确定的东西确定化——告诉AI"按这个规则、在这个位置、用这个命令运行"。约束越具体,生成结果越接近可用。


七、总结

7.1 AI写测试的价值定位

AI写测试代码的价值不是"全自动生成"——是省掉重复的骨架代码。每个Service的测试都要写 @Mock@InjectMocks@BeforeEach 的初始化,每个Controller的测试都要写 MockMvcperform().andExpect()。这些Prompt把骨架交给了AI,人只负责填充业务断言。

7.2 四套模板速查

模板 适用场景 一句话要点
后端单元测试 Service/Controller 约定覆盖三种:正常/null/异常
API接口测试 REST接口 三块缺一不可:正常/鉴权/异常
端到端测试 页面操作 五层断言:UI/网络/数据/体验/质量
全链路一键 提测前 底层往上执行,失败即停
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐