Chapter 08

测试生成与质量提升

测试是 AI 辅助编程中最容易被忽视、也最需要 AI 帮助的领域。Cascade 能生成覆盖边界情况的测试,把"写测试"从苦差事变成几秒的事。

单元测试生成

选中函数或打开文件后,让 Cascade 一键生成完整的测试套件:

为 @src/utils/pricing.ts 中的 calculateDiscount 函数生成完整测试。

测试框架:Vitest + TypeScript
测试文件位置:src/utils/__tests__/pricing.test.ts

测试要求:
1. 正常路径:各种折扣类型(百分比、固定金额)
2. 边界情况:0 折扣、100% 折扣、折扣大于原价
3. 错误情况:负数价格、无效折扣类型、null 输入
4. 测试用例描述用中文
5. 每个测试用例有注释说明测试意图

生成后运行一次测试,如果有失败说明函数可能有 bug。

Cascade 生成的测试示例(针对一个典型的工具函数):

import { describe, it, expect } from 'vitest'
import { calculateDiscount } from '../pricing'

describe('calculateDiscount', () => {

  describe('正常路径 - 百分比折扣', () => {
    it('应该正确计算 10% 折扣', () => {
      expect(calculateDiscount(100, { type: 'percent', value: 10 }))
        .toBe(90)
    })

    it('应该正确计算 50% 折扣', () => {
      expect(calculateDiscount(200, { type: 'percent', value: 50 }))
        .toBe(100)
    })
  })

  describe('正常路径 - 固定金额折扣', () => {
    it('应该正确减去固定金额', () => {
      expect(calculateDiscount(100, { type: 'fixed', value: 20 }))
        .toBe(80)
    })
  })

  describe('边界情况', () => {
    it('0% 折扣应该返回原价', () => {
      expect(calculateDiscount(100, { type: 'percent', value: 0 }))
        .toBe(100)
    })

    it('固定金额大于原价时,最低返回 0(不能为负数)', () => {
      expect(calculateDiscount(50, { type: 'fixed', value: 100 }))
        .toBe(0)
    })
  })

  describe('错误情况', () => {
    it('负数原价应该抛出错误', () => {
      expect(() =>
        calculateDiscount(-100, { type: 'percent', value: 10 })
      ).toThrow('价格不能为负数')
    })

    it('无效折扣类型应该抛出错误', () => {
      expect(() =>
        calculateDiscount(100, { type: 'invalid' as any, value: 10 })
      ).toThrow('无效的折扣类型')
    })
  })
})

测试覆盖率分析

Cascade 不只会生成测试,还可以分析现有测试的覆盖率盲点:

运行测试覆盖率报告:npm run test:coverage
然后分析 @src/services/payment.ts 的覆盖率情况:
1. 哪些代码路径没有被测试覆盖?
2. 哪些分支(if/switch)的某些条件没有被触发?
3. 优先级最高的3个补充测试用例是什么(按业务风险排序)?
4. 生成这3个测试用例

Playwright E2E 测试生成

Cascade 结合 @Web 可以生成 Playwright E2E 测试,覆盖用户操作流程:

为我的 React 购物车功能生成 Playwright E2E 测试。

测试场景(按优先级):
1. 用户登录 → 浏览商品 → 加入购物车 → 结算
2. 购物车修改数量 → 价格实时更新
3. 优惠码输入(有效/无效码)
4. 支付失败的错误处理流程

测试文件:tests/e2e/cart.spec.ts
基础 URL:从 process.env.BASE_URL 读取

使用 Playwright 的 Page Object Model 模式,
创建 CartPage 和 CheckoutPage 两个 Page Object。
// Cascade 生成的 Playwright POM 示例(节选)
import { type Page, type Locator } from '@playwright/test'

export class CartPage {
  readonly page: Page
  readonly cartItems: Locator
  readonly totalPrice: Locator
  readonly checkoutButton: Locator
  readonly couponInput: Locator

  constructor(page: Page) {
    this.page = page
    this.cartItems = page.locator('[data-testid="cart-item"]')
    this.totalPrice = page.locator('[data-testid="cart-total"]')
    this.checkoutButton = page.getByRole('button', { name: '结算' })
    this.couponInput = page.getByPlaceholder('输入优惠码')
  }

  async updateQuantity(productId: string, quantity: number) {
    const item = this.page.locator(`[data-product-id="${productId}"]`)
    await item.getByRole('spinbutton').fill(String(quantity))
    await item.getByRole('spinbutton').press('Tab')
    // 等待价格更新动画完成
    await this.page.waitForSelector('[data-updating="false"]')
  }

  async applyCoupon(code: string) {
    await this.couponInput.fill(code)
    await this.page.getByRole('button', { name: '应用' }).click()
    return this.page.locator('[data-testid="coupon-result"]')
  }
}

JSDoc / TSDoc 文档生成

为现有代码批量添加文档注释,是 Cascade 的高效场景:

为 @src/services/notification.ts 中所有 exported 函数
添加完整的 TSDoc 注释,包括:
- 函数功能描述(一句话)
- @param 每个参数的名称、类型、描述
- @returns 返回值的描述
- @throws 可能抛出的错误
- @example 使用示例(1-2个)

注释用中文,保持与现有代码的缩进一致。
不要修改任何逻辑代码,只添加注释。

AI 代码审查 Checklist

把这个 Checklist 加入 .windsurfrules,让 Cascade 在每次生成代码后自动对照检查:

## AI 代码审查 Checklist(放入 .windsurfrules)

生成代码后,请自动检查以下项目并在输出末尾给出简短报告:

安全 (Security):
□ 没有在代码中硬编码任何密钥或密码
□ SQL 查询使用参数化(防 SQL 注入)
□ 用户输入已经过验证(zod/joi 等)
□ API 响应不会暴露内部错误信息

性能 (Performance):
□ 没有 N+1 数据库查询
□ 数据库查询有必要的索引(WHERE 字段)
□ 大数组操作使用流处理而非一次性加载

可维护性 (Maintainability):
□ 函数名清晰表达意图
□ 没有魔法数字(使用命名常量)
□ 复杂逻辑有注释

错误处理 (Error Handling):
□ 异步操作有 try/catch
□ 错误有有意义的错误消息
□ 不忽略 Promise rejection
测试生成的质量保证 AI 生成的测试需要审查以下几点:① Mock 是否过度(过度 Mock 的测试不能发现真实 bug)② 断言是否有意义(不要只断言 "toBeTruthy()")③ 边界情况是否真实(AI 有时会生成重复的边界情况)④ 测试独立性(测试间不应该共享可变状态)。一条有用的原则:好的测试在代码实现错误时应该失败,而不是永远通过。
本章小结 AI 测试生成最大的价值在于:把"写测试"的摩擦降到零,让开发者没有借口不写测试。Cascade 生成的测试质量取决于 Prompt 的具体程度——明确指定测试框架、文件位置、测试类别(正常/边界/错误)能显著提升质量。Playwright E2E 测试生成 + Page Object Model 是前端自动化测试的最佳实践。