尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Java+Vue端到端测试平台:架构设计与执行引擎实现

发布时间:2026/9/19 17:36:04

资讯中心
01
ARTICLE

Java+Vue端到端测试平台:架构设计与执行引擎实现

Java+Vue端到端测试平台:架构设计与执行引擎实现
简介这份资源面向具备Java与Vue基础的中高级研发与测试开发人员围绕企业级端到端自动化测试平台的设计与实现展开帮助解决回归测试效率低、失败定位难、测试资产分散等痛点可用于构建标准化测试流程并支撑CI/CD质量门禁。资源包为1个docx文档约135KB以图文与代码示例形式呈现完整项目实例。内容涵盖分层架构、测试用例模型、任务调度与状态机、变量作用域解析、断言与报告机制并给出接口请求执行器、断言处理器、任务执行服务等核心代码示例同时包含数据库表设计、API规范、前后端交互逻辑与部署应用说明。读者可据此理解页面与接口混合编排、并发任务资源隔离、异步加载稳定性处理等关键机制并基于完整目录结构与代码进行二次开发或功能扩展。目前已有92人学习适合作为测试平台开发的实践参考。1. 为什么端到端测试平台需要 Java 与 Vue 分工很多团队做自动化测试第一反应是写一堆 Selenium 脚本塞进 CI 里跑。脚本少的时候没问题一旦用例过百、项目过三维护成本就会指数级上升定位器散落在各个文件里测试数据靠硬编码失败原因只能翻控制台日志。这个项目要解决的就是这个问题——把测试资产、执行调度、结果追踪统一到一个平台里。技术选型上后端用 Java Spring Boot前端用 Vue不是随便凑的。Java 的线程池、并发容器和成熟的测试生态JUnit 5、Selenium、RestAssured适合做执行引擎和任务调度Vue 的组件化和响应式适合做用例编排、实时日志和报告展示。两者通过 REST API 和 WebSocket 通信职责边界清晰。这套方案适合有一定 Java 和 Vue 基础、正在从脚本化测试向平台化测试过渡的团队也适合需要把自动化测试接入 CI/CD 流水线的质量保障人员。2. 分层架构与测试用例模型设计2.1 分层架构模型平台整体分为四层接入层、服务层、执行层和存储层。接入层负责 HTTP 请求路由和 WebSocket 连接管理服务层处理项目管理、用例管理、任务调度等业务逻辑执行层封装浏览器驱动和接口调用存储层用 MySQL 持久化测试资产用 Redis 做任务队列和状态缓存。分层的好处是执行引擎不直接依赖具体浏览器实现。比如今天用 Chrome明天要换 Edge 或者远程浏览器节点只需要替换 WebDriverAdapter 的实现类上层调度逻辑不用动。常见做法是把浏览器操作抽象成动作类型点击、输入、跳转、断言每个动作对应一个执行器执行引擎按步骤顺序调用。2.2 测试用例模型测试用例是平台的核心资产。一个用例包含基本信息名称、所属项目、模块、版本和一组有序步骤。每个步骤定义动作类型、目标元素定位方式、输入参数和断言规则。-- 测试用例主表 CREATE TABLE test_case ( id BIGINT PRIMARY KEY AUTO_INCREMENT, project_id BIGINT NOT NULL COMMENT 所属项目, module_name VARCHAR(128) COMMENT 业务模块, case_name VARCHAR(256) NOT NULL, version VARCHAR(32) DEFAULT v1.0, status TINYINT DEFAULT 1 COMMENT 1启用 0禁用, created_by BIGINT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_project_module (project_id, module_name) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 测试步骤表 CREATE TABLE test_step ( id BIGINT PRIMARY KEY AUTO_INCREMENT, case_id BIGINT NOT NULL, step_order INT NOT NULL COMMENT 步骤顺序, action_type VARCHAR(32) NOT NULL COMMENT CLICK/INPUT/NAVIGATE/ASSERT/API_CALL, locator_type VARCHAR(16) COMMENT CSS/XPATH/ID/TEXT, locator_value VARCHAR(512), input_value TEXT COMMENT 支持${var}变量表达式, assert_rule VARCHAR(512) COMMENT 断言表达式, timeout_ms INT DEFAULT 10000, INDEX idx_case_order (case_id, step_order) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;action_type决定了执行引擎调用哪个执行器locator_type和locator_value组合成元素定位策略。input_value支持${orderNo}这种变量表达式执行时从运行上下文里取值替换。timeout_ms是每个步骤独立的超时时间比全局固定等待灵活得多。2.3 任务调度模型任务调度用线程池 阻塞队列实现。任务创建后先写入exec_task表状态为PENDING然后提交到队列。调度器从队列取任务根据当前并发数和资源容量决定是否立即执行。Component public class TaskScheduler { private final ThreadPoolExecutor executor; private final BlockingQueueLong taskQueue new LinkedBlockingQueue(); public TaskScheduler() { this.executor new ThreadPoolExecutor( 2, // 核心线程数 8, // 最大线程数 60L, TimeUnit.SECONDS, new LinkedBlockingQueue(100), new ThreadPoolExecutor.CallerRunsPolicy() ); } public void submit(Long taskId) { taskQueue.offer(taskId); executor.execute(() - { Long id taskQueue.poll(); if (id ! null) { executeTask(id); } }); } private void executeTask(Long taskId) { // 1. 更新任务状态为 RUNNING // 2. 创建独立 ExecutionContext // 3. 按用例顺序执行步骤 // 4. 收集结果写入报告表 // 5. 释放浏览器实例和临时文件 } }核心线程数设为 2、最大 8是因为浏览器实例很吃内存每个 Chrome 进程大概占 200-400MB。如果机器配置一般并发数超过 8 容易把内存打满。CallerRunsPolicy是当队列满时让提交任务的线程自己执行起到背压作用防止任务无限堆积。2.4 变量作用域模型变量分三层全局变量环境级、用例变量用例级、运行时变量步骤执行时产生。解析优先级是运行时 用例 全局。public class VariableResolver { public String resolve(String template, ExecutionContext ctx) { if (template null || !template.contains(${)) { return template; } Pattern pattern Pattern.compile(\\$\\{(\\w)}); Matcher matcher pattern.matcher(template); StringBuffer sb new StringBuffer(); while (matcher.find()) { String key matcher.group(1); String value ctx.getRuntimeVar(key); if (value null) value ctx.getCaseVar(key); if (value null) value ctx.getGlobalVar(key); matcher.appendReplacement(sb, value ! null ? value : ); } matcher.appendTail(sb); return sb.toString(); } }ExecutionContext是每个任务独立创建的里面保存了变量表、浏览器会话、请求头和临时文件路径。任务结束后统一释放避免不同任务之间 Cookie 和 Token 互相污染。3. 执行引擎与断言处理器的代码实现3.1 任务状态枚举与状态转换任务状态用枚举定义状态转换必须合法不能从SUCCESS跳回RUNNING。public enum TaskStatus { PENDING, RUNNING, SUCCESS, FAILED, CANCELLED, TIMEOUT; public boolean canTransitionTo(TaskStatus target) { switch (this) { case PENDING: return target RUNNING || target CANCELLED; case RUNNING: return target SUCCESS || target FAILED || target CANCELLED || target TIMEOUT; default: return false; } } }状态转换校验放在服务层每次更新状态前先调canTransitionTo不合法就抛异常。这样能防止并发场景下状态被错误覆盖。3.2 接口请求执行器接口调用用 RestAssured 封装支持 GET/POST/PUT/DELETE请求头和请求体都从步骤配置里读。Component public class ApiExecutor { public ApiResult execute(TestStep step, ExecutionContext ctx) { String url ctx.resolve(step.getLocatorValue()); String body ctx.resolve(step.getInputValue()); RequestSpecification spec RestAssured.given() .contentType(application/json) .header(Authorization, ctx.getRuntimeVar(token)); Response response; switch (step.getActionType()) { case API_GET: response spec.get(url); break; case API_POST: response spec.body(body).post(url); break; default: throw new IllegalArgumentException(不支持的接口动作: step.getActionType()); } ApiResult result new ApiResult(); result.setStatusCode(response.getStatusCode()); result.setResponseBody(response.getBody().asString()); result.setElapsedMs(response.getTime()); return result; } }ctx.resolve()会把 URL 和请求体里的${var}替换成实际值。Authorization头从运行时变量取登录步骤执行后会把 token 写进上下文。响应结果包含状态码、响应体和耗时全部结构化存储方便后续断言和排查。3.3 断言处理器断言支持多种类型状态码相等、JSON 路径取值相等、包含文本、正则匹配。public class AssertProcessor { public AssertResult process(String assertRule, ApiResult actual) { // 格式: status200 或 json:$.data.orderId ! null AssertResult result new AssertResult(); if (assertRule.startsWith(status)) { int expected Integer.parseInt(assertRule.substring(7)); result.setPassed(actual.getStatusCode() expected); result.setMessage(期望状态码 expected 实际 actual.getStatusCode()); } else if (assertRule.startsWith(json:)) { String path assertRule.substring(5, assertRule.indexOf( )); Object value JsonPath.read(actual.getResponseBody(), path); result.setPassed(value ! null); result.setMessage(JSON路径 path 取值: value); } return result; } }断言规则用字符串表达式配置不用写代码。status200判断状态码json:$.data.orderId判断 JSON 路径是否有值。断言结果包含是否通过和描述信息失败时描述信息会写入步骤执行记录。3.4 任务执行服务任务执行服务把前面几个组件串起来按用例顺序执行步骤每步都记录结果。Service public class TaskExecutionService { Autowired private ApiExecutor apiExecutor; Autowired private AssertProcessor assertProcessor; Autowired private StepRecordMapper stepRecordMapper; public void executeCase(Long caseId, ExecutionContext ctx) { ListTestStep steps stepMapper.selectByCaseId(caseId); for (TestStep step : steps) { StepRecord record new StepRecord(); record.setCaseId(caseId); record.setStepId(step.getId()); record.setStartTime(new Date()); try { ApiResult apiResult apiExecutor.execute(step, ctx); AssertResult assertResult assertProcessor.process( step.getAssertRule(), apiResult); record.setStatus(assertResult.isPassed() ? SUCCESS : FAILED); record.setMessage(assertResult.getMessage()); if (!assertResult.isPassed()) { record.setScreenshotPath(captureScreenshot(ctx)); } } catch (Exception e) { record.setStatus(ERROR); record.setMessage(e.getMessage()); record.setStackTrace(getStackTrace(e)); } finally { record.setEndTime(new Date()); stepRecordMapper.insert(record); } } } }每步执行完立即写库而不是等整个用例跑完再批量写。这样即使任务中途崩溃已经执行的步骤记录不会丢。失败时自动截图截图路径存在screenshot_path字段前端报告页可以直接展示。4. 前后端交互与实时日志推送4.1 统一响应对象与异常处理后端所有接口返回统一格式前端 Axios 拦截器统一处理。public class ApiResponseT { private int code; private String message; private T data; public static T ApiResponseT success(T data) { ApiResponseT r new ApiResponse(); r.code 200; r.message ok; r.data data; return r; } public static T ApiResponseT error(int code, String msg) { ApiResponseT r new ApiResponse(); r.code code; r.message msg; return r; } }全局异常处理器用RestControllerAdvice捕获业务异常和系统异常统一转成ApiResponse.error()。前端只需要判断code 200不用在每个请求里写 try-catch。4.2 WebSocket 实时日志推送任务执行过程中步骤状态和日志需要实时推送到前端。用 Spring WebSocket 的SimpMessagingTemplate按任务 ID 推送。Service public class LogPushService { Autowired private SimpMessagingTemplate messagingTemplate; public void pushStepLog(Long taskId, StepRecord record) { MapString, Object payload new HashMap(); payload.put(stepId, record.getStepId()); payload.put(status, record.getStatus()); payload.put(message, record.getMessage()); payload.put(timestamp, System.currentTimeMillis()); messagingTemplate.convertAndSend(/topic/task/ taskId, payload); } }前端订阅/topic/task/{taskId}收到消息后更新步骤列表的状态和日志。这样测试人员不用刷新页面就能看到执行进度失败步骤会立即标红。4.3 前端 Axios 封装与路由前端 Axios 封装统一加 token、统一处理错误码。import axios from axios import router from /router const request axios.create({ baseURL: /api, timeout: 15000 }) request.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers.Authorization Bearer ${token} } return config }) request.interceptors.response.use( response { const res response.data if (res.code ! 200) { if (res.code 401) { router.push(/login) } return Promise.reject(new Error(res.message)) } return res.data }, error Promise.reject(error) ) export default request请求拦截器自动加 token响应拦截器统一判断业务码。401 直接跳登录页其他错误抛出异常由调用方处理。Vue Router 用beforeEach守卫做登录校验未登录访问受保护路由时重定向到登录页。4.4 执行任务创建与状态监控 GUI任务创建页面让用户选择项目、环境、用例集合和执行策略。提交后跳转到监控页通过 WebSocket 接收实时状态。// 任务监控组件核心逻辑 export default { data() { return { taskId: null, steps: [], ws: null } }, mounted() { this.taskId this.$route.params.taskId this.ws new WebSocket(ws://${location.host}/ws/task/${this.taskId}) this.ws.onmessage (event) { const msg JSON.parse(event.data) const idx this.steps.findIndex(s s.stepId msg.stepId) if (idx 0) { this.$set(this.steps, idx, { ...this.steps[idx], ...msg }) } else { this.steps.push(msg) } } }, beforeDestroy() { if (this.ws) this.ws.close() } }组件挂载时建立 WebSocket 连接收到消息后按stepId更新对应步骤的状态。用$set确保 Vue 能检测到数组元素变化。组件销毁前关闭连接避免内存泄漏。5. 部署要点与失败定位技巧5.1 浏览器执行节点与并发调优浏览器驱动建议单独部署在执行节点上不要和平台服务混在同一台机器。Chrome 无头模式启动参数里加上--no-sandbox、--disable-dev-shm-usage、--disable-gpu能减少容器环境下的启动失败。并发数不是越大越好。我一般按CPU核数 × 1.5估算最大并发同时监控执行节点的内存使用率。如果内存超过 80%就调低最大线程数。任务超时时间建议设为用例平均耗时的 3 倍避免个别慢用例拖垮整个队列。5.2 失败定位的证据链设计失败定位靠的是完整证据链不是一句“用例失败”。平台在四个层级记录信息层级记录内容用途任务层整体状态、开始/结束时间、统计数量快速判断任务是否正常完成用例层用例状态、耗时、失败步骤 ID定位到具体用例步骤层动作类型、请求参数、断言内容、错误信息定位到具体操作附件层截图、页面源码、接口响应、下载文件还原现场所有记录通过taskId、caseId、stepId关联前端报告页从任务逐层下钻到失败步骤。截图用taskId/caseId/stepId.png的路径规则存储方便按目录批量清理。5.3 测试数据一致性与清理机制测试数据污染是端到端测试最常见的坑。平台的做法是每个任务创建时生成唯一runId数据工厂用runId 时间戳 随机序列生成订单号、手机号等唯一数据。任务结束后按runId批量清理测试数据。-- 按运行标识清理测试数据 DELETE FROM test_order WHERE run_id #{runId}; DELETE FROM test_user WHERE run_id #{runId};清理操作放在任务结束的回调里无论成功失败都执行。对于不能删除的数据比如审批记录标记is_test_data 1查询时过滤掉。5.4 持续集成触发接口平台提供 HTTP 接口供 CI 流水线调用创建任务并轮询结果。# 创建执行任务 curl -X POST http://test-platform/api/task/create \ -H Content-Type: application/json \ -H Authorization: Bearer ${TOKEN} \ -d { projectId: 1, envId: 2, caseIds: [101, 102, 103], branch: release/v2.1, retryCount: 1 } # 查询任务状态 curl http://test-platform/api/task/status/${TASK_ID} \ -H Authorization: Bearer ${TOKEN}创建接口返回taskId流水线用taskId轮询状态。任务完成后返回整体状态和统计结果流水线根据status字段决定是否允许进入发布阶段。报告可以导出为 JUnit XML 格式直接接入常见 CI 工具的测试报告展示。一个实用技巧在断言规则里加上json:$.code判断业务码比只看 HTTP 状态码更可靠。很多接口 HTTP 返回 200 但业务码是 500只判断状态码会漏掉这类失败。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。