AI7 min read
AI 辅助测试:用 AI 自动生成单元测试和集成测试
AI 辅助测试:用 AI 自动生成单元测试和集成测试
AI测试单元测试自动化测试Java
写测试是开发者最不喜欢的工作之一。AI 可以自动生成高质量的测试代码。
为什么测试重要但被忽视?
开发者不写测试的原因
- 写测试耗时
- 测试代码枯燥
- 赶进度优先
- 觉得没必要
AI 改变了一切
- AI 生成测试只需几秒
- AI 能覆盖边界情况
- AI 能生成大量测试用例
- 开发者只需审查
AI 生成单元测试
Java + JUnit 5
Prompt:为以下 Java 方法生成单元测试:
- 使用 JUnit 5 + Mockito
- 覆盖正常场景、边界值、异常场景
- 测试方法名用英文,清晰描述测试意图
public class OrderService {
public Order createOrder(Long userId, List<OrderItem> items) {
if (items == null || items.isEmpty()) {
throw new BusinessException("订单商品不能为空");
}
User user = userRepository.findById(userId)
.orElseThrow(() -> new BusinessException("用户不存在"));
BigDecimal total = items.stream()
.map(item -> item.getPrice().multiply(new BigDecimal(item.getQuantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
Order order = new Order();
order.setUserId(userId);
order.setTotal(total);
order.setStatus("CREATED");
return orderRepository.save(order);
}
}
AI 会生成:
@ExtendWith(MockitoExtension.class)
class OrderServiceTest {
@Mock
private UserRepository userRepository;
@Mock
private OrderRepository orderRepository;
@InjectMocks
private OrderService orderService;
@Test
void createOrder_Success() {
Long userId = 1L;
List<OrderItem> items = List.of(
new OrderItem("商品A", new BigDecimal("100"), 2)
);
User user = new User(userId, "testuser");
when(userRepository.findById(userId)).thenReturn(Optional.of(user));
when(orderRepository.save(any(Order.class))).thenAnswer(i -> i.getArgument(0));
Order result = orderService.createOrder(userId, items);
assertNotNull(result);
assertEquals(userId, result.getUserId());
assertEquals(new BigDecimal("200"), result.getTotal());
assertEquals("CREATED", result.getStatus());
}
@Test
void createOrder_EmptyItems_ThrowsException() {
assertThrows(BusinessException.class,
() -> orderService.createOrder(1L, Collections.emptyList()));
}
@Test
void createOrder_NullItems_ThrowsException() {
assertThrows(BusinessException.class,
() -> orderService.createOrder(1L, null));
}
@Test
void createOrder_UserNotFound_ThrowsException() {
when(userRepository.findById(99L)).thenReturn(Optional.empty());
assertThrows(BusinessException.class,
() -> orderService.createOrder(99L, List.of(new OrderItem())));
}
}
Python + pytest
Prompt:为以下 Python 函数生成 pytest 测试:
def calculate_discount(price: float, membership: str) -> float:
if price < 0:
raise ValueError("价格不能为负数")
if membership == "gold":
return price * 0.8
elif membership == "silver":
return price * 0.9
else:
return price
AI 会生成:
import pytest
from discount import calculate_discount
def test_gold_member_discount():
assert calculate_discount(100, "gold") == 80
def test_silver_member_discount():
assert calculate_discount(100, "silver") == 90
def test_normal_member_no_discount():
assert calculate_discount(100, "normal") == 100
def test_zero_price():
assert calculate_discount(0, "gold") == 0
def test_negative_price_raises():
with pytest.raises(ValueError):
calculate_discount(-10, "gold")
def test_large_price():
assert calculate_discount(1000000, "gold") == 800000
AI 生成集成测试
Prompt:为以下 Spring Boot Controller 生成集成测试:
- 使用 @SpringBootTest
- 使用 MockMvc
- 测试所有接口的正常和异常场景
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public User createUser(@Valid @RequestBody CreateUserRequest request) {
return userService.createUser(request);
}
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUser(id);
}
@PutMapping("/{id}")
public User updateUser(@PathVariable Long id, @Valid @RequestBody UpdateUserRequest request) {
return userService.updateUser(id, request);
}
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
}
}
AI 生成 API 测试
Prompt:为以下 API 生成测试用例,用表格形式列出:
POST /api/orders
请求体:{ userId, items: [{productId, quantity}] }
返回:{ orderId, total, status }
列出所有需要测试的场景,包括正常和异常情况。
AI 会生成:
| 场景 | 请求 | 预期结果 |
|---|---|---|
| 正常创建 | 有效数据 | 201, 返回订单 |
| 商品为空 | items: [] | 400, 错误信息 |
| 用户不存在 | 无效 userId | 404, 用户不存在 |
| 库存不足 | 超量购买 | 400, 库存不足 |
| 未登录 | 无 token | 401, 未授权 |
Cursor 生成测试
在 Cursor 中,选中代码后:
Cmd+K输入 "Generate unit tests"- 或者用 Chat:
/tests
Cursor 会自动生成测试代码并插入到文件中。
Claude Code 生成测试
claude > 为 src/service/OrderService.java 生成单元测试
claude > 运行测试并修复失败的用例
测试覆盖率提升
Prompt 模板
分析以下代码的测试覆盖率,找出未覆盖的分支:
[粘贴代码和现有测试]
为每个未覆盖的分支生成测试用例。
自动生成边界测试
为以下方法生成边界值测试:
- 空值
- 零值
- 最大值
- 最小值
- 特殊字符
- 并发场景
[粘贴方法代码]
测试数据生成
生成测试数据
生成 10 条用户测试数据,包含:
- 正常用户
- 边界情况(超长名字、特殊字符)
- 异常情况(空值、无效邮箱)
用 JSON 格式输出。
生成 SQL 测试数据
为 users 表生成 SQL INSERT 测试数据:
- 5 条正常数据
- 2 条边界数据
- 包含 NULL 值
表结构:id, name, email, age, created_at
测试最佳实践
1. AI 生成 + 人工审查
AI 生成的测试需要审查:
- 测试逻辑是否正确
- 是否覆盖关键场景
- 断言是否合理
2. 测试命名规范
// 好的命名
@Test
void createUser_WithValidData_ShouldReturnCreatedUser()
// 差的命名
@Test
void test1()
3. 测试独立性
每个测试应该独立运行,不依赖其他测试。
4. 测试可读性
测试代码要清晰易读,像文档一样。
工具推荐
| 工具 | 特点 | 适合 |
|---|---|---|
| Cursor | IDE 集成 | 日常开发 |
| Claude Code | 命令行 | 批量生成 |
| Diffblue Cover | Java 专用 | Java 项目 |
| CodiumAI | 多语言 | 团队使用 |
总结
AI 辅助测试的价值:
- 效率提升:生成测试从小时级到秒级
- 覆盖率提高:AI 能想到更多边界情况
- 质量提升:测试更全面
- 成本降低:减少测试编写时间
关键:AI 生成,人工审查,持续运行。