货拉拉JS SDK 一体化测试方案的快速实践
一、框架搭建:统一测试工程实现
1. 工程结构设计
创建以Vue为基础的“壳”工程,核心目录结构如下:
js-sdk-test-platform/ ├── src/ │ ├── components/ # 全局组件(含测试通用组件) │ ├── views/ # 测试页面 │ │ ├── testFunctional/ # 功能测试用例目录 │ │ │ ├── testCases/ # 具体测试用例文件 │ │ │ └── index.vue # 测试页面入口 │ │ ├── testPerformance/ # 性能测试用例 │ │ ├── testAutomation/ # 自动化框架 │ │ └── testReport/ # 测试报告页面 │ └── main.ts # 应用入口 ├── playwright/ # 自动化测试执行引擎 │ ├── tests/ │ │ ├── functional/ # 功能测试脚本 │ │ └── performance/ # 性能测试脚本 │ └── reports/ # 测试报告存储
2. 关键技术实现
- 统一编译与部署: 使用Vue打包方案(如Vite)实现多环境兼容,基于Docker镜像构建轻量化部署流程,避免重复环境搭建。
- 版本与资源管理: 通过统一代码库管理测试对象(SDK接口)、测试数据与用例,消除多工程资源割裂问题。
二、功能测试:API二次开发与用例管理
1. 用例拆分与加载机制
- 代码分离实现:
通过
import.meta.glob
动态读取测试用例TS文件,实现前端页面与测试逻辑解耦:
// 读取所有测试用例文件 const allOptionsPath = import.meta.glob('./**.ts', { eager: true }); // 解析并排序用例 const allOptions = Object.keys(allOptionsPath).map(path => { return Object.values(Object.assign({}, allOptionsPath[path]))[0]; }).sort((a, b) => { if (a.groupName === b.groupName) return a.label.length - b.label.length; return a.groupName.localeCompare(b.groupName); });
- 用例分组展示: 通过Vue组件将用例按功能分组(如“基础操作”“图像渲染”),生成可交互测试菜单:
// 用例分组示例 export const MENU_OPTIONS = [{ label: '分组一', key: 'comObj', children: allOptions.map(item => ({ label: item.label, key: `comObj_${item.key}` })) }];
2. 测试用例编写规范
- 核心结构示例:
export default { label: '基础操作', key: 'baseOptions', children: [ { label: 'zIndex减5', key: 'declineZIndex', methods(controller) { checkAndDoAction(controller, (marker) => { const currentZIndex = marker.getZIndex(); if (typeof currentZIndex === 'number') { marker.setZIndex(Math.max(0, currentZIndex - 5)); message.success(`操作后ZIndex为: ${newZIndex}`); } }); } } ] }
三、接口自动化测试:Jasmine+MSW实现
1. 技术选型依据
- Jasmine优势: 自带断言库(expect),无需额外集成;支持浏览器内直接运行,适配SDK图像渲染场景(Jest需额外配置浏览器环境,Mocha集成度低)。
2. 核心实现示例
- 基础接口测试(同步/异步):
describe('baseMap Test suite', () => { let mapInstances: IMap[]; it('setCenter()/getCenter()', done => { const promises = mapInstances.map(async map => { map.setCenter({ lng: 116.45, lat: 39.91 }); await utils.sleep(1000); expect(map.getCenter().lng).toBeCloseTo(116.45, 3); }); Promise.all(promises).then(done).catch(done.fail); }); });
- 异常场景模拟(MSW拦截请求):
import { http, setupWorker } from 'msw'; const worker = setupWorker(); it('searchPoi()异常测试', async () => { // 定义Mock响应 const proxy = http.post('https://api.test.com', async ({ request }) => { // 校验请求参数 const params = new URLSearchParams(request.url.split('?')[1]); expect(params.get('cityId')).toBe('1001'); // 返回错误响应 return HttpResponse.json( { ret: -9, msg: '网络错误' }, { status: 500 } ); }); // 启动Mock服务 await worker.start(); worker.use(proxy); try { await searchPoi({ cityId: '1001' }); } catch (err) { expect(err.message).toContain('错误码:-9'); } finally { await worker.stop(); } });
四、性能测试:Stats.js+Playwright集成
1. 数据采集实现
- 帧率/内存监测:
import Stats from 'stats.js'; const stats = new Stats(); stats.showPanel(0); // 0: FPS, 1: 毫秒, 2: 内存 document.body.appendChild(stats.dom); // 定时采集数据 function collectPerformanceData() { stats.begin(); // 执行性能测试代码 stats.end(); requestAnimationFrame(collectPerformanceData); } collectPerformanceData();
2. 自动化执行链路
- Playwright脚本示例:
// performance.spec.ts import { test, expect } from '@playwright/test'; test('连续setZoom性能测试', async ({ page }) => { // 进入测试页面 await page.goto('http://test-platform/performance'); // 执行测试操作 await page.click('#start-test'); // 等待测试完成 await page.waitForSelector('#test-complete', { timeout: 30000 }); // 提取性能数据 const fpsData = await page.evaluate(() => { // 从Stats.js获取数据 return window.performanceStats.getData(); }); // 断言性能指标 expect(fpsData.avg).toBeGreaterThan(50); // 平均帧率需>50 });
五、智能测试代码生成:DeepSeek API对接
1. 函数定义规范
- 工具函数结构化描述:
{ "type": "function", "function": { "name": "addMarker", "description": "添加地图标记点", "parameters": { "type": "object", "properties": { "position": { "type": "object", "description": "经纬度坐标,格式{lng: number, lat: number}" }, "content": { "type": "string", "description": "标记点显示内容" }, "color": { "type": "string", "description": "标记点颜色(可选)" } }, "required": ["position", "content"] } } }
2. 前后端交互流程
- 后端服务逻辑: 接收前端自然语言需求(如“在上海添加3个标记点”);调用DeepSeek V3 API,携带工具函数定义(如上);解析模型返回的函数调用参数,生成可执行代码:
// Spring Boot服务示例 @PostMapping("/generate-code") public SseEmitter generateCode(@RequestBody UserRequest request) { // 构造工具函数列表 List<ToolFunction> tools = getSdkFunctionList(); // 调用DeepSeek API String code = deepSeekClient.call( request.getRequirement(), tools ); // 流式返回代码 emitter.send(SseEmitter.event().name("code").data(code)); return emitter; }
- 前端接收与渲染: 通过SSE流式接收代码片段,实时展示并支持语法高亮:
六、关键技术对比与实践要点
框架搭建 | Vue + Playwright | 多环境兼容、组件化复用 | 需统一测试数据格式与版本管理 |
功能测试 | import.meta.glob动态加载 | 用例与页面解耦,便于维护 | 需规范用例编写模板,避免逻辑冗余 |
自动化测试 | Jasmine + MSW | 浏览器原生支持、异常模拟便捷 | 异步测试需正确处理done()回调 |
性能测试 | Stats.js + Playwright | 实时数据采集、自动化链路完整 | 需设置合理的测试时长与性能阈值 |
智能生成 | DeepSeek + Function Calling | 自然语言转代码,降低开发门槛 | 需完善工具函数定义,补充参数约束说明 |