研发效能 # 🚀 测试效能工具:一键扫码上传文件,让测试机与 PC 高效互通!

孤千羽 · 2025年10月31日 · 最后由 newman 回复于 2025年10月31日 · 640 次阅读

💡 背景与痛点

在日常测试工作中,测试工程师经常会遇到这样的烦恼:

  1. 测试移动端应用时,需要抓包、截图、录屏,并把这些内容发给开发定位问题。
  2. 但测试机上往往不能登录个人微信。
  3. 公司也没有足够多的测试微信号可用。
  4. 导致文件和信息传输非常低效。

有时候仅仅为了把一个截图发给开发,可能要经历「拍照 → 传到自己手机 → 微信转发 → 再传到 PC」这样的繁琐流程。

🧰 我开发的解决方案:扫码上传助手

基于这些痛点,我开发了一个轻量级的测试效能小工具 —— 扫码上传助手 🧩。

它的目标非常简单: 让测试机与 PC 之间传文件,像发微信一样方便。


✨ 功能特点

✅ PC 端自动生成二维码

每次启动时,PC 端会自动生成一个上传二维码,并展示在浏览器页面上。 扫码后即可进入对应的上传通道。

二维码页面示意图



二维码页面示意

✅ 手机扫码即可上传

测试机打开微信扫码(或浏览器扫码)二维码后,自动跳转到上传页面。

上传文件(截图、录屏、日志等)后,PC 端页面会实时接收并显示文件

手机上传界面示意



手机上传界面示意

手机上传中显示进度



手机上传中显示进度

✅ 实时消息传递

除了文件,测试人员还可以直接发送文字消息到 PC 端,比如:

「复现步骤」「异常时间点」「接口返回错误码」等。

实时消息示意

实时消息示意

✅ 跨设备,无需登录、无需微信号

手机端无需登录账号,也不需要安装 App。

只要能扫码、能上传,就能使用。

真正实现测试机与 PC 的轻量级高效互通


⚙️ 技术架构

整个系统采用 前后端分离架构
📱 手机端(H5 上传页面)
⇅ HTTP / WebSocket
🖥️ PC 端(浏览器显示 + WebSocket 监听)

☁️ 服务端(Spring Boot)

  • 后端:Spring Boot + WebSocket + 定时任务
  • 前端:Vue + Element UI
  • 通信方式:WebSocket 实时推送
  • 文件存储:服务器静态目录映射

🔑 技术关键点实现

1️⃣ 二维码生成接口

通过 ZXing 生成带任务 ID 的二维码,扫描后跳转上传页:

@Slf4j
@RestController
@RequestMapping("qrcode")
public class QrCodeController {

    @Value("${frontend.url}")
    private String frontendUrl;

    @GetMapping("/{taskId}")
    public ResponseEntity<String> generateQRCode(@PathVariable String taskId) throws Exception {
        String baseUrl = frontendUrl + "/upload?taskId=" + URLEncoder.encode(taskId, StandardCharsets.UTF_8.name());
        int width = 300, height = 300;
        Map<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        BitMatrix bitMatrix = new QRCodeWriter().encode(baseUrl, BarcodeFormat.QR_CODE, width, height, hints);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        MatrixToImageWriter.writeToStream(bitMatrix, "PNG", baos);
        String base64 = "data:image/png;base64," + Base64.getEncoder().encodeToString(baos.toByteArray());
        return StatusCode.OK.build(base64);
    }
}

2️⃣ 文件上传接口

支持多文件与文字消息上传,上传后通过 WebSocket 实时推送到前端展示:

@PostMapping("/files")
public ResponseEntity<List> upload(@RequestParam String taskId,
                                   @RequestParam(value = "files", required = false) List<MultipartFile> files,
                                   @RequestParam(value = "content", required = false) String content) throws IOException {
    List<UploadMessage> list = new ArrayList<>();

    // 发送文本消息
    if (content != null && !content.isEmpty()) {
        UploadMessage textMsg = new UploadMessage();
        textMsg.setTime(LocalDateTime.now().toString());
        textMsg.setContent(content);
        UploadWebSocket.broadcast(taskId, textMsg);
        list.add(textMsg);
    }

    // 上传文件
    if (files != null) {
        for (MultipartFile file : files) {
            String fileName = System.currentTimeMillis() + "_" + file.getOriginalFilename();
            String uploadDir = staticLocation + "/upload/other/";
            File dest = new File(uploadDir, fileName);
            dest.getParentFile().mkdirs();
            file.transferTo(dest);

            UploadMessage msg = new UploadMessage();
            msg.setTime(LocalDateTime.now().toString());
            msg.setFileUrl("static/upload/other/" + fileName);
            UploadWebSocket.broadcast(taskId, msg);
            list.add(msg);
        }
    }

    return StatusCode.OK.build(list);
}

3️⃣ WebSocket 实时通信

每个二维码对应一个 WebSocket 任务通道,用于推送实时消息:

@Slf4j
@Component
@ServerEndpoint(value="/ws/upload/{taskId}")
public class UploadWebSocket {

    // taskId -> set of sessions (多个客户端可以订阅同一个 taskId)
    private static final Map<String, Set<Session>> SESSION_MAP = new ConcurrentHashMap<>();
    private static final ObjectMapper MAPPER = new ObjectMapper();

    private String taskId;

    @OnOpen
    public void onOpen(Session session, @PathParam("taskId") String taskId) {
        this.taskId = taskId;
        SESSION_MAP.computeIfAbsent(taskId, k -> Collections.newSetFromMap(new ConcurrentHashMap<>())).add(session);
    }

    @OnMessage
    public void onMessage(Session session, String message, @PathParam("taskId") String taskId) {
        // 可处理客户端消息(例如心跳),这里忽略
    }

    @OnClose
    public void onClose(Session session, @PathParam("taskId") String taskId) {
        Set<Session> set = SESSION_MAP.get(taskId);
        if (set != null) set.remove(session);
    }

    @OnError
    public void onError(Session session, Throwable thr) {
        // 日志忽略
    }

    public static void broadcast(String taskId, UploadMessage msg) {
        Set<Session> sessions = SESSION_MAP.getOrDefault(taskId, Collections.emptySet());
        if (sessions.isEmpty()) return;
        try {
            String text = MAPPER.writeValueAsString(msg);
            // 迭代发送(并发安全)
            for (Session s : sessions) {
                if (s.isOpen()) {
                    try { s.getBasicRemote().sendText(text); } catch (Exception ignored) {}
                }
            }
        } catch (Exception ignored) {}
    }
}

使用步骤

1️⃣ 启动服务端
运行 Spring Boot 项目,打开浏览器访问二维码生成页。

2️⃣ 扫描二维码
测试机用微信 / 浏览器扫码,跳转上传页面。

3️⃣ 上传文件或消息
上传截图、视频或输入文字说明。

4️⃣ PC 端实时显示结果
上传后内容自动推送并显示在 PC 端界面。


🔚 结语

这个 扫码上传工具 虽然小巧,但解决了我们测试工作中一个长期的痛点。它让测试人员能更专注于 问题定位与分析,而不是被低效的文件传输方式拖慢节奏。
如果你也经常为测试机与 PC 之间传文件发愁,不妨试试开发这个工具 👇💬 欢迎留言告诉我你的建议!后续我还计划支持:上传后自动通知开发(Webhook)。

共收到 2 条回复 时间 点赞

大佬牛啊,能优化做成手机截图上传然后直接在电脑桌面上生成文件的吗;因为上传到电脑上其实还是要保存文件再提交到 bug 工具上 这个步骤还是多的

能实现反向吗,PC 端上传,手机端扫码下载。

3楼 已删除
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册