第6章 AI驱动的质量保证-代码和提示词-林子雨编著《AI编程》

大数据学习路线图

林子雨编著《AI编程》(访问教材官网

6.2 开发阶段质量保证

6.2.1 代码格式化

Black是Python社区最流行的代码格式化工具,它的安装非常简单,具体命令如下:

pip install black

安装完成后,不带任何参数执行即可:

# 格式化当前目录下的所有文件
black . 
# 格式化单个文件(直接覆盖原文件)
black my_script.py 
# 格式化整个目录(递归处理所有 .py)
black src/ 
# 同时格式化多个目标
black src/ tests/ main.py

也可以在执行之前,先检查一下Black将会执行哪些格式化操作:

# 只检查是否有文件需要格式化,不改写
black --check .
# 查看上一条命令的返回码,0=没问题,1=需要格式化
echo $? 
# 打印出差分diff,但不改写
black --diff src/my_file.py 
# 两个一起用
black --check --diff .

不带任何参数执行Black,将会对该文件自动进行格式化:

black port_check.py

安装isort的命令如下:

pip install isort

isort的使用方式和Black非常类似,如下所示:

# 格式化当前目录
isort . 
# 格式化单个文件(直接覆盖)
isort my_script.py 
# 格式化整个目录(递归)
isort src/ 
# 多个目标
isort src/ tests/ main.py 
# 只检查,不写回
isort --check-only .
# 查看上一条命令的返回码,0=OK,1=需要整理
echo $? 
# 打印 diff
isort --diff src/main.py 
# 组合使用
isort --check-only --diff .

6.2.2 静态分析

安装Ruff的命令如下:

pip install ruff

Ruff的使用方式如下:

# 只检查(不改文件)——最安全
ruff check app/  # 检查app目录,这里只是举例,本章并不存在该目录 
# 自动修复可修项(例如删掉未使用import、排序import)
ruff check --fix app/ 
# 只看某类问题(例如只看import排序相关)
ruff check --select I app/

6.2.3 类型检查

安装mypy的命令如下:

pip install mypy

6.2.4 辅助检查

安装Vulture的命令如下:

pip install vulture

6.3 校验反馈闭环机制

6.3.1 钩子框架的安装与初始化

安装pre-commit的命令如下(只要安装一次,不需要为每个项目安装):

pip install pre-commit

安装完成后,在项目根目录执行如下命令(需要为每个项目单独安装,以后开发其他项目,需要为其他项目也执行一次安装命令):

pre-commit install

如果在安装pre-commit时遇到下面这样的错误,则需要先取消全局设置,再重新安装。如下所示:

# 遇到错误
pre-commit install
[ERROR] Cowardly refusing to install hooks with `core.hooksPath` set.
hint: `git config --unset-all core.hooksPath`
# 取消全局设置
git config --global --unset-all core.hooksPath
# 重新安装
% pre-commit install
# 看到这个提示,则说明安装成功
pre-commit installed at .git/hooks/pre-commit

6.3.2 检查规则配置

以下是一个整合了6.2节所有检查的完整配置,可以保存在项目根目录下的“.pre-commit-config.yaml”文件中直接使用:

repos:
  - repo: https://github.com/psf/black
    rev: 24.8.0
    hooks:
      - id: black
        language_version: python3.11

  - repo: https://github.com/pycqa/isort
    rev: 5.13.2
    hooks:
      - id: isort
        args: ["--profile", "black"]

  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.6.4
    hooks:
      - id: ruff
        args: ["--fix"]

  - repo: https://github.com/jendrikseipp/vulture
    rev: v2.11
    hooks:
      - id: vulture
        args: [
          "--min-confidence=80",
          "--sort-by-size",
          "."
          ]

  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v1.11.2
    hooks:
      - id: mypy
        name: mypy type checking
        args: [
          "--ignore-missing-imports",
          "--show-error-codes",
          "--cache-dir=.mypy_cache"
        ]

  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.6.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-json

6.4 AI辅助测试

6.4.2 AI辅助用例生成

下面以一个密码强度检测脚本为例,演示如何通过TRAE使用因果图方法生成测试用例。密码检测脚本的业务逻辑如下:

# password_checker.py

password = input("请输入密码: ")

has_digit = any(c.isdigit() for c in password)
has_alpha = any(c.isalpha() for c in password)
has_special = any(c in "!@" for c in password)
length_ok = 8 <= len(password) <= 16

if has_digit and has_alpha and has_special and length_ok:
    print("Strong")
else:
    print("Weak")

在TRAE中,使用“Agent”模式,在智能体交互界面的对话框中输入以下提示词并提交,请求TRAE使用因果图方法生成测试用例:

你是一个资深的测试专家,精通测试领域的各种方法论。

请用「因果图法」设计测试用例,规则如下:
1. 输入(因)与输出(果)的关系:恒等、非、或、与;
2. 输入之间的约束:互斥、包含、唯一、要求、屏蔽;
3. 执行步骤:
   第一步:从需求提取输入/输出,画因果图,标注关系与约束;
   第二步:由因果图生成判定表;
   第三步:判定表每行转成 1 条测试用例。

输出要求:
- 先按 第一步/第二步/第三步 给出简要推理;
- 最后只输出一张 Markdown 表格形式的测试用例,其余内容全部省略。

请为password_checker.py生成测试用例。

6.4.3 AI辅助接口测试

安装命令如下:

pip install pytest httpx pytest-asyncio pytest-cov

安装完依赖后,可以运行接口测试。假设测试文件名为test_api.py,常用命令如下:

# 运行所有测试,-v表示详细输出
pytest test_api.py -v 
# 运行指定测试函数
pytest test_api.py::test_create_user_success -v 
# 显示更详细的输出(包括打印内容)
pytest test_api.py -v -s 
# 生成覆盖率报告
pytest test_api.py --cov=src --cov-report=html

测试覆盖率是衡量测试质量的重要指标,它表示测试用例覆盖了多少源代码。pytest-cov插件可以生成详细的覆盖率报告:

# 运行测试并生成覆盖率报告
pytest test_api.py --cov=src --cov-report=term-missing 
# 生成HTML格式的覆盖率报告(可浏览器查看)
pytest test_api.py --cov=src --cov-report=html

下面以4.5小节的待办事项应用为例,演示如何通过TRAE生成接口测试。在TRAE中选择“Agent”模式,在智能体交互界面的对话框中输入如下提示词并提交:

你是资深测试开发专家 (Python/FastAPI/pytest 方向)

请你根据用户提供的FastAPI代码,生成可直接运行的pytest接口功能测试脚本。

执行步骤:
  1. 识别所有路由和HTTP方法
  2. 解析Pydantic模型构造请求体
  3. 为每个接口生成正常和异常场景测试
  4. 使用httpx.AsyncClient测试

代码规范:使用pytest+httpx+pytest-asyncio,断言覆盖status_code和response body关键字段

输出要求:最后只输出pytest测试代码,其余内容全部省略。

通过下面的命令执行接口测试:

pytest test_api.py -v

6.4.4 AI辅助端到端测试

Playwright的安装非常简单,在项目目录下执行以下命令:

npm init -y
npm install -D @playwright/test @types/node

然后,在package.json中添加如下测试脚本(package.json是Node.js的配置文件,是由AI自动生成的):

{
  "scripts": {
    "test": "playwright test",
    "test:headed": "playwright test --headed",
    "report": "playwright show-report"
  }
}

下面是在TRAE中对第4章的待办事项应用进行端到端测试生成时使用的提示词:

你是资深测试开发(TS+Playwright Test),根据FastAPI源码生成可直接运行端到端测试: 
 1. 识别全部路由、请求方式、参数; 
 2. 解析Pydantic模型,组装正常/异常请求体; 
 3. 采用Playwright内置request发起请求。 

 规范:基于Playwright Test,断言状态码+返回关键字段,代码放tests目录。 
 输出:在当前目录下创建一个e2e目录,生成端到端测试代码,并给出执行方式。

执行端到端测试的步骤如下:

# 1. 进入e2e目录并安装依赖
cd e2e
npm install 
# 2. 安装Playwright浏览器(首次运行需要)
npx playwright install chromium 
# 3. 在另一个终端启动FastAPI服务
cd ..
uvicorn main:app --reload
 # 4. 运行测试
npm test 
# 5. 查看测试报告
npm run report

6.4.5 AI辅助性能测试

Locust的安装非常简单,通过pip一行命令即可完成:

pip install locust

接下来为4.5小节的待办事项应用增加性能测试。由于目前的待办事项应用只提供了获取所有待办事项、新增待办事项和更新待办事项3个接口,为了模拟标准的增、删、改、查,可以在TRAE对话框中,通过提示词编程为应用增加两个新的接口,用以获取某一个待办事项和删除某一个待办事项,这里假设两个新的接口的代码如下:

@app.get("/todos/{todo_id}")
async def get_todo(todo_id: int) -> dict:
    conn = get_db_connection()
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM todos WHERE id = ?", (todo_id,))
    todo = cursor.fetchone()
    conn.close()
    if todo is None:
        raise HTTPException(status_code=404, detail="Todo not found")
    return {
        "id": todo["id"],
        "title": todo["title"],
        "is_completed": bool(todo["is_completed"]),
        "created_at": todo["created_at"]
    }

@app.delete("/todos/{todo_id}", status_code=204)
async def delete_todo(todo_id: int):
    conn = get_db_connection()
    cursor = conn.cursor()
    cursor.execute("DELETE FROM todos WHERE id = ?", (todo_id,))
    conn.commit()
    if cursor.rowcount == 0:
        conn.close()
        raise HTTPException(status_code=404, detail="Todo not found")
    conn.close()
    return None

接下来,让TRAE根据这五个API端点自动生成Locust压测脚本,只需要通过提示词让TRAE生成压测脚本即可:

为当前项目增加locust的压测脚本,要求覆盖到当前项目的所有API,并且读写API的比例为3:1。

启动待办事项应用后,在终端执行以下命令,以Headless模式运行压测:

locust -f locustfile.py --host=http://localhost:8000 --headless -u 100 -t 60s --csv=results/report --loglevel=WARNING