ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

AI 辅助写单测:如何覆盖边界,而不是凑覆盖率

2026/8/24 22:38:49 拓冰建站 浏览量
AI 辅助写单测:如何覆盖边界,而不是凑覆盖率 文章目录开篇本文不会讨论什么一、覆盖率高为什么仍然可能没有覆盖风险二、先从需求和风险生成测试场景三、边界不是“传个 null”这么简单1. 输入边界2. 状态边界3. 时间边界4. 依赖边界5. 并发边界四、让 AI 写测试前先告诉它“应该观察什么”1. 返回值2. 数据状态3. 依赖调用4. 消息和事件5. 日志和审计五、AI 生成单测时最容易出现的 6 个问题1. 测试和实现绑定得太紧2. 只验证“调用了”不验证“调用是否正确”3. Mock 返回值过于理想4. 断言过于宽松5. 测试数据没有表达业务含义6. 测试只验证当前实现没有验证需求六、用一个真实场景设计测试矩阵七、让 AI 先生成测试设计再生成测试代码第一轮测试设计第二轮生成测试代码八、把线上故障转成回归测试九、单测、集成测试和端到端测试怎么分工十、如何判断一组 AI 生成的测试是否有价值十一、我的 AI 单测 Prompt十二、总结✍创作者全栈弄潮儿²⁰²⁶ 个人主页全栈弄潮儿²⁰²⁶ 专栏地址AI 编程进阶实战开篇让 AI 写单测最常见的用法是请为这个方法生成单元测试。几秒钟后AI 可能会生成一组看起来很完整的测试一个正常输入测试。一个空值测试。一个异常测试。一个成功返回测试。测试数量不少代码也能运行。但这并不代表测试真的有价值。很多测试只是把实现代码重新描述了一遍输入有效参数 调用方法 断言返回成功它们可能让覆盖率上升却没有回答真正重要的问题业务规则是否被验证状态不允许时是否会拒绝操作重复请求会不会产生重复数据外部依赖失败后数据是否保持一致权限不足时敏感操作是否被阻止修复一个线上问题后测试能否防止它再次出现上一篇文章我们讨论了如何把排障上下文交给 AI。排障结束后最有价值的动作之一就是把已经确认的故障条件转成自动化测试。这篇文章重点讨论如何让 AI 帮你设计真正覆盖边界的单测而不是帮你凑出一个漂亮的覆盖率数字。本文不会讨论什么单元测试不是测试工作的全部也不是覆盖率越高越好。本文不会认为 100% 覆盖率就代表代码没有问题。建议为每一行代码机械地生成一个测试。用 Mock 代替所有真实依赖验证。认为 AI 生成的测试天然符合业务预期。把测试数量、断言数量和测试价值画等号。本文关注的是一套更实用的思路先识别业务风险 ↓ 再列出边界场景 ↓ 设计可观察结果 ↓ 让 AI 生成测试 ↓ 执行并审查测试一、覆盖率高为什么仍然可能没有覆盖风险假设有这样一个下单方法publicOrderResultcreateOrder(CreateOrderCommandcommand){validate(command);CouponcouponcouponService.find(command.getCouponId());MoneyamountpriceCalculator.calculate(command,coupon);OrderorderorderRepository.save(command,amount);eventPublisher.publish(newOrderCreatedEvent(order.getId()));returnOrderResult.success(order.getId());}AI 可能很快生成以下测试1. 有效商品和优惠券创建成功。 2. command 为空抛出异常。 3. couponService 返回优惠券。 4. orderRepository 被调用一次。 5. eventPublisher 被调用一次。这些测试能够覆盖主流程和部分分支。但它们可能遗漏优惠券已经过期。优惠券不属于当前用户。商品价格在查询后发生变化。库存不足但订单已经写入。数据库写入成功事件发布失败。同一个请求重复提交。当前用户没有创建订单权限。订单创建成功但返回响应时连接断开。覆盖率解决的是“代码是否被执行过”。它不一定解决“系统是否在危险情况下表现正确”。所以我会把测试目标拆成三层层次要回答的问题执行覆盖这段代码是否被测试走到行为覆盖正常和异常行为是否符合预期风险覆盖关键边界和线上风险是否被证明真正有价值的单测至少要达到第二层涉及核心业务时还要尽量覆盖第三层。二、先从需求和风险生成测试场景不要一上来让 AI 读取方法并生成测试代码。第一步应该是让它先设计测试场景请先不要生成测试代码。 请根据以下需求和验收标准设计测试场景 需求 用户可以使用优惠券创建订单。 规则 - 只能使用当前用户拥有的优惠券。 - 已过期优惠券不能使用。 - 已使用优惠券不能重复使用。 - 库存不足时不能创建订单。 - 订单创建失败时不能产生已扣库存状态。 - 同一个幂等键重复提交最终只能创建一个订单。 请按以下类别输出 1. 正常流程。 2. 参数边界。 3. 业务状态。 4. 权限安全。 5. 依赖失败。 6. 并发和幂等。 7. 数据一致性。 每个场景包含前置条件、操作、预期结果、需要验证的副作用。这一步的输出应该是一张场景表而不是测试代码。示例类别场景预期结果重点验证正常有效优惠券和充足库存创建成功订单和事件各一次状态优惠券已过期创建失败不写订单、不扣库存权限使用他人优惠券拒绝请求不泄露优惠券信息依赖库存服务超时返回可识别错误不产生部分成功幂等相同幂等键并发提交只有一个订单数据库只有一条记录三、边界不是“传个 null”这么简单AI 生成测试时最容易把边界理解成空值和负数。但业务边界通常还包括状态、时序、数据量和系统依赖。1. 输入边界null、空字符串和空集合。最小值、最大值和超长值。非法格式和特殊字符。重复元素和数量过大。2. 状态边界未创建、处理中、已完成、已取消。已过期、已使用、已删除。当前用户拥有和不拥有。资源存在和不存在。3. 时间边界刚好到期。到期前一秒和到期后一秒。跨时区和跨天。重试窗口和超时窗口。4. 依赖边界返回空结果。返回错误码。超时。部分成功。重复响应。依赖版本或配置不一致。5. 并发边界两个相同请求同时到达。第一次请求成功但响应丢失。消息被重复消费。数据在查询和写入之间被其他请求修改。可以让 AI 对已有测试做一次“边界反查”请不要根据测试数量评价质量。 请反向检查当前测试集还缺少哪些边界 1. 输入边界。 2. 状态边界。 3. 时间边界。 4. 依赖失败边界。 5. 并发和幂等边界。 每个遗漏场景请说明 - 为什么它重要。 - 可能造成什么后果。 - 应该观察什么结果。四、让 AI 写测试前先告诉它“应该观察什么”测试不是为了让方法执行一次而是为了证明结果正确。因此在生成测试代码前我会先定义可观察结果。1. 返回值断言返回订单号、状态和错误类型符合预期。2. 数据状态断言成功时订单被写入失败时订单没有新增或状态没有错误变化。3. 依赖调用断言库存预占成功后才允许写订单。 断言优惠券校验失败时不会调用扣库存。4. 消息和事件断言成功只发布一次事件失败不发布错误事件。5. 日志和审计断言安全操作产生审计记录但不包含完整手机号和令牌。可以使用下面的 Prompt请为下面的测试场景设计“可观察结果”暂时不要写代码。 请分别说明 1. 应该断言什么返回值。 2. 应该检查什么数据库状态。 3. 哪些依赖应该被调用或不应该被调用。 4. 是否需要检查事件、缓存、日志或审计。 5. 哪些结果不能只通过 Mock 验证。这一步可以减少只断言notNull、只断言方法被调用一次这类低价值测试。五、AI 生成单测时最容易出现的 6 个问题1. 测试和实现绑定得太紧如果测试大量验证私有方法、内部变量和具体调用顺序代码一重构测试就全部失效。更好的测试优先验证对外行为。业务结果。重要副作用。失败后的状态。2. 只验证“调用了”不验证“调用是否正确”下面的断言价值有限verify(repository).save(any());还应该确认保存的是哪个用户的数据。金额和状态是否正确。保存发生在什么条件下。失败时是否根本不应该调用。3. Mock 返回值过于理想AI 经常让所有依赖都返回成功结果库存成功、支付成功、数据库成功、消息成功。这只能覆盖最顺利的主流程。要主动要求它生成空结果。异常。超时。错误码。重复响应。部分成功。4. 断言过于宽松例如assertNotNull(result);这无法证明状态、金额、错误类型和资源状态正确。断言应该尽量描述业务结果而不是只证明“返回了一个对象”。5. 测试数据没有表达业务含义如果测试中到处都是test,1,2,true,null读者很难知道这些值为什么重要。建议使用有意义的数据构造CreateOrderCommandcommandcommandOf(userId(user-42),couponId(coupon-expired),quantity(2));6. 测试只验证当前实现没有验证需求如果实现里错误地把“优惠券不存在”当作“无需优惠”而测试也按照这个逻辑断言测试就会把缺陷固定下来。所以测试场景应该先来自需求和验收标准再来自代码分支。六、用一个真实场景设计测试矩阵假设有一个“修改手机号”服务输入用户 ID、新手机号、旧手机号验证码 规则 - 只能修改当前用户自己的手机号。 - 验证码必须正确且未过期。 - 新手机号不能被其他用户占用。 - 修改成功后发送安全通知。 - 修改失败时原手机号保持不变。可以先让 AI 设计矩阵场景前置条件操作预期结果副作用正常修改验证码正确新手机号未占用提交修改修改成功发送一次通知验证码错误验证码错误提交修改返回验证码错误手机号不变验证码过期验证码过期提交修改返回验证码过期手机号不变越权修改请求用户不是当前用户提交修改拒绝访问不查询敏感信息手机号占用新手机号已被占用提交修改返回业务错误手机号不变重复提交相同请求重复提交连续提交行为符合幂等规则通知不重复并发修改两个请求修改同一用户并发提交只有一个结果生效数据不覆盖错误通知失败手机号已保存通知服务失败提交修改按约定返回或补偿记录失败状态注意最后一行。“手机号已保存但通知失败”到底算成功还是失败不应该由测试作者自行决定而应该先确认业务规则。七、让 AI 先生成测试设计再生成测试代码我建议把过程拆成两轮。第一轮测试设计请根据需求、验收标准和现有代码设计测试矩阵。 要求 - 暂时不要写测试代码。 - 先覆盖正常、边界、状态、权限、异常、并发和幂等场景。 - 每个场景写清前置条件、操作、预期结果和副作用。 - 标记哪些规则尚未确认。 - 按风险优先级排序。第二轮生成测试代码请根据已经确认的测试矩阵生成单元测试。 要求 1. 遵循当前项目已有测试风格。 2. 优先验证业务行为和重要副作用。 3. 不要为了覆盖率测试私有实现细节。 4. 对外部依赖明确区分成功、空结果、异常、超时和重复响应。 5. 测试名称要表达业务场景和预期结果。 6. 每个测试只验证一个主要行为。 7. 生成代码后说明每个测试覆盖了哪条业务规则。如果 AI 直接生成了测试代码也可以让它回头生成“测试与规则映射表”检查是否有重要规则没有对应测试。八、把线上故障转成回归测试Day 16 讲过排障时应该记录触发条件。实际现象。时间线。关键日志。最终根因。这些内容可以直接转换为回归测试请根据下面的线上故障记录设计一个最小回归测试。 线上现象 用户重复点击提交后创建了两条订单。 已确认根因 请求在查询幂等记录和插入订单之间存在竞态。 请说明 1. 测试前置数据。 2. 并发或重复请求的触发方式。 3. 最终必须断言的数据状态。 4. 该测试应该放在单元、集成还是端到端层。 5. 如果单测无法可靠复现还需要什么更高层测试。一个好的回归测试不只是证明“这次 Bug 修好了”还要尽量保留当时的触发条件。九、单测、集成测试和端到端测试怎么分工不是所有边界都适合用单测覆盖。场景更适合的测试层参数校验和纯业务计算单元测试Service 与 Repository 的事务行为集成测试数据库唯一约束和并发写入集成测试或并发测试消息发布与消费集成测试第三方接口真实协议契约测试或集成测试完整用户流程端到端测试可以让 AI 帮你判断测试层级请判断下面每个测试场景适合放在哪一层单元、集成、契约或端到端。 判断依据包括 1. 是否需要真实数据库约束。 2. 是否需要真实事务边界。 3. 是否需要消息或网络交互。 4. 是否需要验证多个模块协作。 5. 是否需要真实用户入口。 不要为了运行速度把必须依赖真实系统行为的场景强行改成单测。十、如何判断一组 AI 生成的测试是否有价值我会从下面几个角度检查[ ] 每个关键业务规则都有至少一个测试场景 [ ] 测试不只有成功路径 [ ] 边界覆盖了输入、状态、时间、依赖和并发 [ ] 失败时的数据状态也有断言 [ ] 重要副作用有明确验证 [ ] Mock 没有把真正要验证的行为全部替换掉 [ ] 断言表达业务结果而不是只断言对象不为空 [ ] 测试数据能看出业务含义 [ ] 测试名称能说明场景和预期 [ ] 线上故障已经转成回归测试 [ ] 需要真实数据库或消息的场景没有被错误地伪装成单测 [ ] 测试失败时能帮助定位问题最后一项尤其重要。如果测试失败后只能看到“expected true but was false”它对排障帮助很小。十一、我的 AI 单测 Prompt下面是一份可以直接复用的完整 Prompt请作为一名重视业务风险的测试工程师协助我为下面的代码设计和生成测试。 一、需求和验收标准 填写业务需求、规则和验收标准 二、项目上下文 填写技术栈、测试框架、已有测试风格和依赖约束 三、待测试代码 填写代码、调用方、返回值和关键依赖 四、已知风险 填写边界、线上故障、权限、并发和数据一致性风险 请分两阶段工作。 第一阶段只输出测试设计不写测试代码。 - 按正常、边界、状态、异常、安全、并发、幂等分类。 - 每个场景包含前置条件、操作、预期结果和副作用。 - 指出需要人工确认的规则。 - 标记适合的测试层级。 第二阶段等待我确认测试设计后再生成测试代码。 生成代码时要求 - 使用当前项目已有测试风格。 - 测试名称表达业务场景。 - 优先验证行为和结果不测试无价值的内部细节。 - 对成功、空结果、异常、超时和重复响应分别设计测试。 - 对失败场景断言数据没有错误变化。 - 对并发和幂等风险说明单元测试是否足够。 - 每个测试标注覆盖的业务规则。 最后输出测试覆盖矩阵并列出仍然没有被证明的风险。十二、总结AI 可以很快写出大量单测但测试的价值不在数量而在于它是否证明了重要行为。一组高价值测试应该覆盖正常流程。输入边界。业务状态。权限和安全。依赖失败。并发和幂等。数据一致性。线上问题回归。我会坚持这套节奏先从需求识别风险 ↓ 再设计测试矩阵 ↓ 明确应该观察什么 ↓ 让 AI 生成测试代码 ↓ 执行并审查测试质量请记住覆盖率告诉你代码走过哪些路好的测试还要告诉你走错路时系统会怎样。下一篇文章我们继续进入工程判断用 AI 做重构前评估哪些代码值得改哪些别碰。如果这篇文章对你有帮助欢迎点赞、收藏、关注专栏。也欢迎在评论区留言你让 AI 写单测时最容易遗漏边界、异常还是并发场景✍坚持原创求关注点赞收藏