货拉拉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

自然语言转代码,降低开发门槛

需完善工具函数定义,补充参数约束说明

全部评论
这篇文章是之前带我的mentor写的,发现他又开发了一个这么牛逼的平台。不得不感慨货拉拉真是越做越好了,羡慕呀!这辈子还能回去吗
1 回复 分享
发布于 昨天 19:10 山东

相关推荐

不愿透露姓名的神秘牛友
06-25 18:11
点赞 评论 收藏
分享
评论
1
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务