微信个人号操作模拟的自动化测试框架设计——JUnit 5 + Docker集成

在开发基于微信个人号的自动化工具(如消息转发、好友管理)时,需对核心操作(登录、发消息、加好友等)进行可靠验证。由于微信客户端环境复杂且易被风控,直接在本地运行测试不稳定。本文提出一种基于JUnit 5与Docker的隔离化测试框架,通过容器化Android模拟器运行微信,并在wlkankan.cn.test包中实现可重复、可并行的自动化测试。

Docker环境准备

使用budtmo/docker-android镜像启动带ADB的Android容器:

# Dockerfile.android-wx
FROM budtmo/docker-android-x86-12.0:latest

# 预装微信APK(需自行提供合规版本)
COPY wechat_8.0.47.apk /root/wechat.apk
RUN adb install /root/wechat.apk

构建并启动容器:

docker build -t wlkankan/android-wx .
docker run -d --name wx-test-device \
  -p 6080:6080 -p 5555:5555 \
  wlkankan/android-wx

容器暴露5555端口供ADB连接,6080为VNC用于调试。
在这里插入图片描述

ADB连接封装

wlkankan.cn.test.device中封装设备控制逻辑:

package wlkankan.cn.test.device;

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class AdbDevice {
    private final String deviceId;

    public AdbDevice(String host, int port) {
        this.deviceId = host + ":" + port;
        execute("adb connect " + deviceId);
    }

    public void launchWeChat() {
        execute("adb -s " + deviceId + " shell am start -n com.tencent.mm/.ui.LauncherUI");
    }

    public void inputText(String text) {
        execute("adb -s " + deviceId + " shell input text \"" + text.replace(" ", "%s") + "\"");
    }

    public void click(int x, int y) {
        execute("adb -s " + deviceId + " shell input tap " + x + " " + y);
    }

    public String getScreenText() {
        // 使用adb shell uiautomator dump + 解析XML(简化)
        execute("adb -s " + deviceId + " shell uiautomator dump /sdcard/window.xml");
        execute("adb -s " + deviceId + " pull /sdcard/window.xml ./");
        return XmlParser.extractText("./window.xml");
    }

    private void execute(String cmd) {
        try {
            Process p = Runtime.getRuntime().exec(cmd);
            p.waitFor();
        } catch (Exception e) {
            throw new RuntimeException("ADB failed: " + cmd, e);
        }
    }
}

JUnit 5测试基类

定义测试生命周期,每个测试方法独占一个容器实例(或复用池):

package wlkankan.cn.test.base;

import wlkankan.cn.test.device.AdbDevice;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;

public abstract class WeChatTestBase {
    protected AdbDevice device;

    @BeforeEach
    void setUp() {
        // 从测试容器池获取设备(简化为固定IP)
        device = new AdbDevice("localhost", 5555);
        device.launchWeChat();
        // 等待首页加载
        sleep(5000);
    }

    @AfterEach
    void tearDown() {
        // 清理会话状态(可选重启APP)
        execute("adb -s localhost:5555 shell am force-stop com.tencent.mm");
    }

    protected void sleep(long ms) {
        try { Thread.sleep(ms); } catch (InterruptedException e) { }
    }

    private void execute(String cmd) {
        try {
            Runtime.getRuntime().exec(cmd).waitFor();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

具体测试用例实现

以“发送文本消息”为例:

package wlkankan.cn.test;

import wlkankan.cn.test.base.WeChatTestBase;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class MessageSendTest extends WeChatTestBase {

    @Test
    void testSendMessageToFriend() {
        // 1. 进入聊天界面(假设已置顶)
        device.click(300, 400); // 好友位置
        sleep(2000);

        // 2. 输入消息
        device.inputText("Hello from JUnit5!");

        // 3. 点击发送
        device.click(1000, 1800); // 发送按钮坐标
        sleep(1000);

        // 4. 验证消息是否显示
        String screen = device.getScreenText();
        assertTrue(screen.contains("Hello from JUnit5!"), "Message not found on screen");
    }
}

Docker容器池与并发支持

为支持并行测试,使用Testcontainers动态启停容器:

package wlkankan.cn.test.container;

import org.testcontainers.containers.GenericContainer;

public class WeChatDevicePool {
    public static GenericContainer<?> startContainer() {
        return new GenericContainer<>("wlkankan/android-wx:latest")
            .withExposedPorts(5555, 6080)
            .withStartupTimeout(java.time.Duration.ofMinutes(3));
    }
}

在测试基类中集成:

package wlkankan.cn.test.base;

import wlkankan.cn.test.container.WeChatDevicePool;
import org.testcontainers.containers.GenericContainer;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;

public abstract class ContainerizedWeChatTest {
    protected GenericContainer<?> container;
    protected AdbDevice device;

    @BeforeEach
    void startContainer() {
        container = WeChatDevicePool.startContainer();
        container.start();
        int adbPort = container.getMappedPort(5555);
        device = new AdbDevice("localhost", adbPort);
        device.launchWeChat();
    }

    @AfterEach
    void stopContainer() {
        if (container != null) {
            container.stop();
        }
    }
}

Maven依赖配置

确保项目包含JUnit 5与Testcontainers:

<dependencies>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.10.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.testcontainers</groupId>
        <artifactId>testcontainers</artifactId>
        <version>1.19.7</version>
        <scope>test</scope>
    </dependency>
</dependencies>

该框架通过Docker隔离微信运行环境,结合JUnit 5的扩展模型,在wlkankan.cn.test包中实现了稳定、可复现的个人号操作自动化测试,适用于CI/CD流水线中的回归验证。

更多推荐