ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从 AI Plan 模式到全栈项目实战:测试用例管理系统搭建指南

从 AI Plan 模式到全栈项目实战:测试用例管理系统搭建指南 最近在整理一套 AI 测试用例管理项目时发现一个很实用的协作思路先用 AI 的 Plan 模式把需求和技术方案理清楚再让它按模块逐个生成代码整个过程比传统手工搭建快很多。这篇文章基于实际落地过程整理成一份完整教程包含 Plan 模式的用法说明、全栈项目目录设计、数据库脚本、后端接口、前端页面和常见坑点新手可以直接照着搭有经验的开发者也能用来规范自己的 AI 辅助开发流程。1. Plan 模式是什么为什么要用它1.1 从手动改写代码到 AI 规划式开发很多开发者第一次用 AI 编程工具时习惯直接描述需求让 AI 一次性输出整段代码。这种方式在小功能上很快但遇到“测试用例管理系统”这种同时包含前端页面、后端接口、数据库设计、权限控制的全栈项目时一次性生成的代码往往会出现结构混乱、重复代码多、数据库字段前后不一致等问题。Plan 模式解决的就是这个问题。它不会立即生成代码而是先根据你的需求输出一份完整的实施计划。计划里会包含项目模块如何划分数据库表结构设计后端接口清单前端页面与组件拆分功能实现的先后顺序每步的验收标准。你可以先审查这份计划发现问题直接修改等计划确认后再让 AI 按计划逐块实现代码。这样生成的代码整体一致性更高模块边界也更清晰。1.2 常见工作模式手动、Plan、自动在使用 AI 编程工具时经常看到“手动模式”“Plan 模式”“自动模式”等说法。不同工具对这些模式的命名略有差异但含义基本一致模式类型工作方式适用场景手动模式你逐条发送指令AI 按指令执行每一步都等待你确认精确改代码、查问题、单点修改Plan 模式AI 先分析需求并输出方案确认后再实施项目初始化、重构、多模块功能开发自动模式AI 根据目标自动迭代执行连续修改多个文件已完成规划后的批量编码实现这三种模式不是互斥的甚至可以结合使用。比如项目初期用 Plan 模式确定框架中期用自动模式生成批量样板代码后期用手动模式精准修复问题。理解这些模式的区别能显著提升 AI 辅助开发的效率。1.3 为什么 AI 测试用例项目适合用 Plan 模式起步测试用例管理项目非常典型它包含了数据建模、接口设计、前端表单、列表展示、统计分析等常见的全栈开发要素。用它作为 Plan 模式的练手项目有几点明显收益需求容易拆解用户、用例、测试计划、执行结果等模块边界清楚。技术栈是通用栈数据库 后端接口 前端页面几乎每个开发都熟悉。可运行、可验证搭好后能真实录入数据、查询数据、统计结果能直观看到效果。便于扩展后续还能增加用户登录、权限控制、Excel 导入导出、批量执行等能力。所以这篇文章以“AI 测试用例管理系统”为目标完整演示如何用 Plan 模式从零搭好全栈项目框架。2. 环境准备与项目总体设计2.1 本地环境要求本文的示例涉及前后端分离项目环境版本根据你自己的电脑情况调整我这里给出一个常见组合JDK8 或 11 以上示例以 Java 17 编写如果你本机是 8需要适当调整 pom 中的版本配置Maven3.6 以上MySQL5.7 或 8.0Node.js16 以上IDEIntelliJ IDEA 或 VS Code 均可AI 编程工具支持 Plan 模式的 CLI 或 IDE 插件均可如果你没有安装 JDK 或 Node.js建议先安装完成后再继续。下面的示例命令以 macOS / Linux 环境为主Windows 用户将路径和命令稍作调整即可。2.2 项目整体功能范围我们搭建的 AI 测试用例管理系统初版只做最核心的闭环用例管理新增、查询、修改、删除测试用例用例字段用例名称、所属模块、优先级、前置条件、操作步骤、预期结果执行记录记录每条用例最后一次执行结果数据统计按模块统计用例数量、按结果类型统计通过率。这样一个范围足以覆盖“前后端 数据库”的完整链路又不至于让项目规模过大。2.3 技术栈与目录规划建议采用前后端分离结构ai-test-case-project/ ├── backend/ # Spring Boot 后端 │ ├── src/main/java/ │ ├── src/main/resources/ │ └── pom.xml ├── frontend/ # Vue3 前端 │ ├── src/ │ ├── index.html │ ├── package.json │ └── vite.config.js ├── database/ │ └── init.sql └── docs/ ├── 01-需求文档.md ├── 02-设计文档.md └── 03-接口文档.md等下我们会让 AI 按这个结构生成对应代码。先规划好目录可以避免后续文件乱放。3. 用 Plan 模式生成项目框架的具体步骤3.1 向 AI 描述完整需求使用 Plan 模式时第一件事不是让 AI 直接写代码而是把需求描述清楚。以下是一个可以直接复制使用的需求描述模板请用 Plan 模式帮我规划一个 AI 测试用例管理系统。 需求背景 测试团队需要维护测试用例方便查看用例详情、快速筛选用例、统计执行结果。 功能需求 1. 用例管理支持新增、编辑、删除、查询测试用例 2. 用例字段用例名称、所属模块、优先级高/中/低、前置条件、操作步骤、预期结果 3. 执行记录记录每条用例的执行结果通过/失败/阻塞 4. 统计报表按模块展示用例数量按执行结果展示通过率 5. 提供 RESTful 接口供前端页面调用。 技术栈 后端Spring Boot 3 MyBatis-Plus MySQL 前端Vue 3 Vite Element Plus Axios 数据库MySQL 5.7 或 8.0 补充要求 1. 数据库表结构要合理包含创建时间、更新时间 2. 后端接口遵循统一返回格式 3. 前端页面简洁包含用例列表、新增用例弹窗、统计面板 4. 需要输出项目目录结构和接口清单。 请先不要写完整代码先输出实施方案包括模块划分、数据库表设计、接口清单、前端页面结构、开发顺序。这段描述的关键词是“先输出实施方案”AI 会据此进入规划状态而不是立即埋头写代码。3.2 审核 AI 输出的实施计划AI 输出计划后不要急着点“确认”或“继续”先检查下面几个方面模块划分是否覆盖所有需求点数据库表是否包含全部字段接口清单能否支撑前端页面的数据交互开发顺序是否按“数据库 → 后端 → 前端”推进。如果计划有缺漏可以直接在对话里补充比如计划里缺少“删除用例”的接口请补充 统计接口除了通过率还需要返回每个模块的用例数量 前端页面加入一个“重置查询条件”的按钮。Plan 模式的价值就在这里它允许你在没有产出大量代码前低成本调整方案。一旦方案确认后续生成代码就有了明确依据。3.3 确认计划后分批生成代码计划确认后让 AI 按顺序生成代码建议一批一批来而不是一次性生成所有文件。示例指令如下请按计划开始实施 第一步生成 database/init.sql 数据库初始化脚本 第二步生成后端项目的 pom.xml、application.yml、实体类、Mapper、Service、Controller 第三步生成前端项目结构、API 封装、用例列表页面、新增用例弹窗、统计面板。 每一步生成完成后请等待我确认再继续下一步。分批生成的好处是如果某一步代码有误方便单独纠正不需要从头再来。4. 实战AI 测试用例系统代码实现下面是我用 Plan 模式逐步整理出来的核心代码。由于文章篇幅有限这里给出最关键的文件完整代码可以按同样方式让 AI 补齐。4.1 数据库脚本 database/init.sql-- 创建数据库 CREATE DATABASE IF NOT EXISTS test_case_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE test_case_db; -- 测试用例表 CREATE TABLE IF NOT EXISTS test_case ( id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT 主键ID, case_name VARCHAR(200) NOT NULL COMMENT 用例名称, module_name VARCHAR(100) NOT NULL COMMENT 所属模块, priority VARCHAR(10) NOT NULL DEFAULT 中 COMMENT 优先级高/中/低, precondition TEXT COMMENT 前置条件, steps TEXT COMMENT 操作步骤, expected_result TEXT COMMENT 预期结果, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT测试用例表; -- 用例执行结果表 CREATE TABLE IF NOT EXISTS test_case_result ( id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT 主键ID, case_id BIGINT NOT NULL COMMENT 用例ID, result VARCHAR(20) NOT NULL COMMENT 执行结果通过/失败/阻塞, executor VARCHAR(50) COMMENT 执行人, execute_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 执行时间, remark VARCHAR(500) COMMENT 备注, CONSTRAINT fk_case_result FOREIGN KEY (case_id) REFERENCES test_case(id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用例执行结果表; -- 初始化一条示例数据 INSERT INTO test_case (case_name, module_name, priority, precondition, steps, expected_result) VALUES (登录功能-正确账号密码登录, 登录模块, 高, 已注册测试账号, 1. 打开登录页\n2. 输入正确账号密码\n3. 点击登录, 登录成功跳转首页);这里使用了utf8mb4字符集是为了兼容中文和特殊字符。外键约束fk_case_result保证执行记录必须关联到真实存在的用例避免脏数据。4.2 后端 Spring Boot 核心代码4.2.1 pom.xml 依赖配置?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.2.5/version relativePath/ /parent groupIdcom.example/groupId artifactIdtest-case-backend/artifactId version1.0.0/version nametest-case-backend/name descriptionAI 测试用例管理系统后端/description properties java.version17/java.version mybatis-plus.version3.5.5/mybatis-plus.version /properties dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version${mybatis-plus.version}/version /dependency dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependencies build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId configuration excludes exclude groupIdorg.projectlombok/groupId artifactIdlombok/artifactId /exclude /excludes /configuration /plugin /plugins /build /project如果你本机 JDK 版本是 8需要把java.version改为 8同时 Spring Boot 3 最低要求是 Java 17建议直接使用 JDK 17 以上。4.2.2 application.yml 配置server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/test_case_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: root jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: Asia/Shanghai mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: id-type: auto配置里map-underscore-to-camel-case: true的作用是把数据库字段case_name自动映射为 Java 属性caseName这样实体类里就不用手动写一堆映射注解。4.2.3 实体类 TestCase.java// 文件路径backend/src/main/java/com/example/testcase/entity/TestCase.java package com.example.testcase.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.time.LocalDateTime; Data TableName(test_case) public class TestCase { TableId(type IdType.AUTO) private Long id; private String caseName; private String moduleName; private String priority; private String precondition; private String steps; private String expectedResult; private LocalDateTime createTime; private LocalDateTime updateTime; }使用 MyBatis-Plus 时实体类字段和数据库字段通过驼峰转换自动映射所以不用每个字段都加TableField注解。Data是 Lombok 提供的编译后自动生成 getter/setter代码更简洁。4.2.4 Mapper 接口// 文件路径backend/src/main/java/com/example/testcase/mapper/TestCaseMapper.java package com.example.testcase.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.example.testcase.entity.TestCase; import org.apache.ibatis.annotations.Mapper; Mapper public interface TestCaseMapper extends BaseMapperTestCase { }Mapper 接口继承BaseMapperT后无需编写 XML就自动拥有插入、查询、更新、删除等基础方法。4.2.5 Service 与实现类// 文件路径backend/src/main/java/com/example/testcase/service/TestCaseService.java package com.example.testcase.service; import com.baomidou.mybatisplus.core.metadata.IPage; import com.example.testcase.entity.TestCase; import java.util.List; public interface TestCaseService { IPageTestCase pageQuery(int pageNum, int pageSize, String moduleName, String priority); TestCase getById(Long id); int add(TestCase testCase); int update(TestCase testCase); int delete(Long id); }// 文件路径backend/src/main/java/com/example/testcase/service/impl/TestCaseServiceImpl.java package com.example.testcase.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.example.testcase.entity.TestCase; import com.example.testcase.mapper.TestCaseMapper; import com.example.testcase.service.TestCaseService; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import jakarta.annotation.Resource; Service public class TestCaseServiceImpl implements TestCaseService { Resource private TestCaseMapper testCaseMapper; Override public IPageTestCase pageQuery(int pageNum, int pageSize, String moduleName, String priority) { LambdaQueryWrapperTestCase wrapper new LambdaQueryWrapper(); wrapper.like(StringUtils.hasText(moduleName), TestCase::getModuleName, moduleName) .eq(StringUtils.hasText(priority), TestCase::getPriority, priority) .orderByDesc(TestCase::getCreateTime); return testCaseMapper.selectPage(new Page(pageNum, pageSize), wrapper); } Override public TestCase getById(Long id) { return testCaseMapper.selectById(id); } Override public int add(TestCase testCase) { return testCaseMapper.insert(testCase); } Override public int update(TestCase testCase) { return testCaseMapper.updateById(testCase); } Override public int delete(Long id) { return testCaseMapper.deleteById(id); } }分页查询使用了 MyBatis-Plus 的LambdaQueryWrapper条件用动态判断moduleName为空时不拼接该查询条件。这种方式比手动拼接 SQL 更安全也能避免 SQL 注入问题。4.2.6 统一返回结果封装// 文件路径backend/src/main/java/com/example/testcase/common/Result.java package com.example.testcase.common; import lombok.Data; Data public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(success); result.setData(data); return result; } public static T ResultT error(String message) { ResultT result new Result(); result.setCode(500); result.setMessage(message); return result; } }4.2.7 控制器 Controller// 文件路径backend/src/main/java/com/example/testcase/controller/TestCaseController.java package com.example.testcase.controller; import com.baomidou.mybatisplus.core.metadata.IPage; import com.example.testcase.common.Result; import com.example.testcase.entity.TestCase; import com.example.testcase.service.TestCaseService; import org.springframework.web.bind.annotation.*; import jakarta.annotation.Resource; RestController RequestMapping(/api/test-case) CrossOrigin public class TestCaseController { Resource private TestCaseService testCaseService; GetMapping(/page) public ResultIPageTestCase page( RequestParam(defaultValue 1) int pageNum, RequestParam(defaultValue 10) int pageSize, RequestParam(required false) String moduleName, RequestParam(required false) String priority) { return Result.success(testCaseService.pageQuery(pageNum, pageSize, moduleName, priority)); } GetMapping(/{id}) public ResultTestCase getById(PathVariable Long id) { return Result.success(testCaseService.getById(id)); } PostMapping(/add) public ResultVoid add(RequestBody TestCase testCase) { testCaseService.add(testCase); return Result.success(null); } PutMapping(/update) public ResultVoid update(RequestBody TestCase testCase) { testCaseService.update(testCase); return Result.success(null); } DeleteMapping(/{id}) public ResultVoid delete(PathVariable Long id) { testCaseService.delete(id); return Result.success(null); } }CrossOrigin是为了解决本地开发时的前后端跨域问题。生产环境建议用 Nginx 反向代理或者在网关层统一配置跨域规则而不是在每个 Controller 上直接加注解。4.2.8 启动类// 文件路径backend/src/main/java/com/example/testcase/TestCaseApplication.java package com.example.testcase; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; SpringBootApplication MapperScan(com.example.testcase.mapper) public class TestCaseApplication { public static void main(String[] args) { SpringApplication.run(TestCaseApplication.class, args); } }4.3 前端 Vue3 核心代码4.3.1 创建 Vite 项目npm create vitelatest frontend -- --template vue cd frontend npm install element-plus axios npm run dev4.3.2 API 请求封装// 文件路径frontend/src/api/request.js import axios from axios; import { ElMessage } from element-plus; const request axios.create({ baseURL: http://localhost:8080, timeout: 10000 }); request.interceptors.response.use( response { const res response.data; if (res.code ! 200) { ElMessage.error(res.message || 请求失败); return Promise.reject(new Error(res.message)); } return res; }, error { ElMessage.error(error.message || 网络异常); return Promise.reject(error); } ); export default request;4.3.3 用例 API 模块// 文件路径frontend/src/api/testCase.js import request from ./request; export function pageQuery(params) { return request.get(/api/test-case/page, { params }); } export function addTestCase(data) { return request.post(/api/test-case/add, data); } export function updateTestCase(data) { return request.put(/api/test-case/update, data); } export function deleteTestCase(id) { return request.delete(/api/test-case/${id}); }4.3.4 用例列表页面!-- 文件路径frontend/src/views/TestCaseList.vue -- template div classpage-container el-card shadownever el-form :inlinetrue el-form-item label模块 el-input v-modelquery.moduleName placeholder请输入模块名称 clearable / /el-form-item el-form-item label优先级 el-select v-modelquery.priority placeholder请选择优先级 clearable el-option label高 value高 / el-option label中 value中 / el-option label低 value低 / /el-select /el-form-item el-form-item el-button typeprimary clickloadData查询/el-button el-button clickresetQuery重置/el-button el-button typesuccess clickopenAddDialog新增用例/el-button /el-form-item /el-form el-table :datatableData border stripe el-table-column propid labelID width70 / el-table-column propcaseName label用例名称 / el-table-column propmoduleName label模块 width120 / el-table-column proppriority label优先级 width90 / el-table-column propexpectedResult label预期结果 show-overflow-tooltip / el-table-column label操作 width160 template #defaultscope el-button sizesmall clickopenEditDialog(scope.row)编辑/el-button el-button sizesmall typedanger clickhandleDelete(scope.row.id)删除/el-button /template /el-table-column /el-table el-pagination v-model:current-pagequery.pageNum v-model:page-sizequery.pageSize :totaltotal layouttotal, prev, pager, next current-changeloadData / /el-card !-- 新增/编辑弹窗 -- el-dialog v-modeldialogVisible :titleisEdit ? 编辑用例 : 新增用例 width600px destroy-on-close el-form refformRef :modelform label-width100px el-form-item label用例名称 required el-input v-modelform.caseName placeholder请输入用例名称 / /el-form-item el-form-item label所属模块 el-input v-modelform.moduleName placeholder请输入所属模块 / /el-form-item el-form-item label优先级 el-select v-modelform.priority el-option label高 value高 / el-option label中 value中 / el-option label低 value低 / /el-select /el-form-item el-form-item label前置条件 el-input v-modelform.precondition typetextarea / /el-form-item el-form-item label操作步骤 el-input v-modelform.steps typetextarea / /el-form-item el-form-item label预期结果 el-input v-modelform.expectedResult typetextarea / /el-form-item /el-form template #footer el-button clickdialogVisible false取消/el-button el-button typeprimary clicksubmitForm确定/el-button /template /el-dialog /div /template script setup import { reactive, ref, onMounted } from vue; import { ElMessage, ElMessageBox } from element-plus; import { pageQuery, addTestCase, updateTestCase, deleteTestCase } from ../api/testCase; const tableData ref([]); const total ref(0); const dialogVisible ref(false); const isEdit ref(false); const query reactive({ pageNum: 1, pageSize: 10, moduleName: , priority: }); const defaultForm () ({ id: null, caseName: , moduleName: , priority: 中, precondition: , steps: , expectedResult: }); const form reactive(defaultForm()); const loadData async () { const res await pageQuery(query); tableData.value res.data.records; total.value res.data.total; }; const resetQuery () { query.moduleName ; query.priority ; query.pageNum 1; loadData(); }; const openAddDialog () { isEdit.value false; Object.assign(form, defaultForm()); dialogVisible.value true; }; const openEditDialog (row) { isEdit.value true; Object.assign(form, { id: row.id, caseName: row.caseName, moduleName: row.moduleName, priority: row.priority, precondition: row.precondition, steps: row.steps, expectedResult: row.expectedResult }); dialogVisible.value true; }; const submitForm async () { if (!form.caseName) { ElMessage.warning(请输入用例名称); return; } if (isEdit.value) { await updateTestCase(form); ElMessage.success(修改成功); } else { await addTestCase(form); ElMessage.success(新增成功); } dialogVisible.value false; loadData(); }; const handleDelete async (id) { await ElMessageBox.confirm(确定删除该用例吗, 提示, { type: warning }); await deleteTestCase(id); ElMessage.success(删除成功); loadData(); }; onMounted(loadData); /script这个页面集中展示了列表查询、条件筛选、分页、弹窗表单、新增、编辑、删除等常见操作是全栈项目中最常出现的页面形态也是 Plan 模式生成代码时最有代表性的产物。4.4 运行与验证后端启动cd backend mvn spring-boot:run前端启动cd frontend npm run dev打开浏览器访问http://localhost:3000应该能看到用例列表页面。如果页面能正常加载用例数据并且新增、编辑、删除都能生效说明前后端链路已经打通。4.5 结果说明初始化时init.sql插入了一条登录用例数据。启动后进入页面默认表格应该能显示这条数据。点击“新增用例”填写字段并保存列表会自动刷新并显示新数据。这里体现的完整流程是前端发送请求后端 Controller 接收请求Service 调用 MapperMyBatis-Plus 执行 SQL数据写入 MySQL前端刷新列表展示最新数据。调试时如果接口报错可以先看后端的控制台日志。MyBatis-Plus 配置了StdOutImpl日志会打印实际执行的 SQL方便定位是字段映射问题还是 SQL 拼接问题。5. 常见问题与排查思路5.1 前端跨域请求报错现象浏览器控制台出现Access-Control-Allow-Origin相关报错接口能通但页面拿不到数据。原因前端运行在http://localhost:3000后端运行在http://localhost:8080端口不同浏览器默认阻止跨源访问。解决思路开发环境先在 Controller 上添加CrossOrigin注解或在WebMvcConfigurer中配置全局跨域生产环境优先使用 Nginx 反向代理前端请求统一转发到后端不要在生产环境使用*通配跨域应指定具体来源域名。5.2 MyBatis-Plus 分页不生效现象调用selectPage返回的总数正确但records里数据不全或 SQL 中没有出现LIMIT语句。原因MyBatis-Plus 3.5 以上版本需要手动配置分页插件。解决思路新增一个配置类注册MybatisPlusInterceptor并添加PaginationInnerInterceptor。// 文件路径backend/src/main/java/com/example/testcase/config/MybatisPlusConfig.java package com.example.testcase.config; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); PaginationInnerInterceptor paginationInnerInterceptor new PaginationInnerInterceptor(DbType.MYSQL); paginationInnerInterceptor.setMaxLimit(500L); interceptor.addInnerInterceptor(paginationInnerInterceptor); return interceptor; } }这个坑很常见很多 AI 生成的代码里容易漏掉分页插件配置。遇到分页不生效时优先检查这一步。5.3 项目启动后端口占用现象后端启动时提示Port 8080 was already in use。原因本机已有其他进程占用 8080 端口。解决思路查找占用进程并结束或者修改application.yml中server.port为其他端口如果修改了后端端口前端request.js中的baseURL也要同步修改。5.4 数据库连接失败现象启动时提示Access denied for user rootlocalhost或Unknown database test_case_db。原因MySQL 账号密码错误或者没有先执行init.sql创建数据库。解决思路先执行数据库脚本确认test_case_db已创建核对application.yml中的username和password确认 MySQL 服务已启动如果使用 MySQL 8 以上版本driver 使用com.mysql.cj.jdbc.Driver通常没问题低版本驱动会出现连接失败。5.5 AI 生成的代码一键粘贴后跑不起来现象代码看起来没问题但启动报错或页面白屏。原因AI 生成的代码可能面向不同目录结构、包名、版本直接粘贴可能不完全适配。解决思路优先让 AI 按“整个文件路径”输出而不是零散代码片段检查包名是否和启动类一致检查前端依赖是否全部安装检查数据库表是否存在让 AI 阅读报错信息后自行修复把完整异常堆栈发给它通常比人肉排查更快。6. 最佳实践与工程建议6.1 Plan 模式提示词模板沉淀建议把适合 Plan 模式的提示词沉淀成团队文档。一套好的提示词应该包含“项目目标、功能范围、技术栈、目录建议、输出要求”五个要素。这样以后再做同类项目只要替换其中的业务描述就可以快速得到一份高质量实施方案。6.2 AI 生成代码必须人工审查AI 生成代码能大幅提升效率但不代表可以直接跳过审查。重点关注以下方面SQL 语句特别是批量更新、删除语句必须确认是否带 WHERE 条件接口鉴权逻辑不能裸奔暴露敏感数据配置文件中是否包含明文密码、密钥异常处理是否捕获了数据库连接失败等情况生产环境相关配置是否写在application-prod.yml中隔离。尤其是数据库变更任何更新、删除操作都应在测试库中验证备份确认影响范围后再在正式环境执行。6.3 配置敏感信息管理目前application.yml中直接写了数据库密码。本地开发可以接受但项目如需共享或部署到正式环境建议使用环境变量替代明文密码使用配置中心管理多环境配置数据库账号按最小权限分配不直接使用 root 账号。6.4 测试用例项目本身的数据设计建议作为测试用例管理系统它的核心价值在于用例的结构化和可追溯性。实际项目落地时建议增加用例与需求的关联字段便于做需求覆盖率统计增加用例与缺陷的关联执行失败时能直接关联缺陷单增加用例附件能力上传测试截图或测试数据文件记录用例历史版本变更时可以回溯支持批量导入导出方便与 Excel 测试用例模板互通。这些能力在初版框架稳定后可以分批加入。每个新功能都建议先走一遍 Plan 模式确认方案后再编码。6.5 前后端协作规范当项目变大后建议提前约定前后端协作规范接口路径统一/api/模块名/动作返回结构统一{ code, message, data }日期时间格式统一yyyy-MM-dd HH:mm:ss分页参数统一pageNum、pageSize接口文档使用 Swagger / Knife4j 自动生成或者用 Apifox 维护在线接口文档。这套规范越早定下来团队协作的摩擦越小。7. 总结与后续学习路线通过这次实操我们完成了 AI 测试用例系统的全栈框架搭建核心收获有三个理解 Plan 模式的工作方式先规划后编码能有效避免项目从第一步就陷入混乱。手动模式适合精调细节自动模式适合方案确认后的批量实现三种模式结合使用效率最高。掌握了一个典型全栈项目的完整结构数据库初始化脚本、Spring Boot 后端接口、Vue3 前端页面、接口调用链贯穿前后端。积累了一批高频坑点的排查思路跨域配置、分页插件、数据库连接、AI 代码适配问题遇到类似场景可以直接复用。下一步建议按顺序做三件事给项目增加用户登录和权限管理让普通用户只能操作自己创建的用例管理员可以管理所有人增加用例执行记录模块按计划执行用例并生成通过率和缺陷统计报表引入自动化测试脚本让用例执行结果能自动回填到系统中形成从测试设计到测试执行的闭环。如果这篇文章对你有帮助可以收藏备用。实际动手跑一遍项目比收藏十篇教程更有效。遇到 AI 生成代码跑不起来的情况不要急着全部推翻先把报错信息整理清楚发给 AI 让它自己修往往能省下不少时间。
返回列表