You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Appium Android自动化测试中拆分脚本并保持应用运行状态?

Appium拆分脚本保持应用持续运行的可行性及实现方案

当然可行!这种场景在Appium自动化测试里太常见了——尤其是当你想把测试逻辑拆分成不同阶段(比如把登录作为前置步骤,后续执行业务流程测试),同时避免重复启动应用带来的时间损耗。下面给你详细讲讲具体的实现思路和方法:

核心思路:复用同一个Appium Driver实例

Appium的Driver实例是和设备/应用会话绑定的,只要你不调用driver.quit(),这个会话就会一直保持,应用也不会被关闭。所以实现需求的关键,就是让第二部分脚本能拿到第一部分创建好的Driver实例,继续操作。


方式一:借助测试框架的全局会话机制(推荐)

如果你用JUnit、TestNG(Java)或者Pytest(Python)这类测试框架,完全可以利用它们的全局前置/后置钩子来初始化一次Driver,然后让多个测试方法复用这个实例。这种方式最规范,也最容易维护。

示例1:TestNG(Java)

import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.MobileElement;
import org.openqa.selenium.By;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.*;
import java.net.URL;

public class AppSplitTest {
    // 全局Driver实例,所有测试方法共享
    private static AndroidDriver<MobileElement> driver;

    @BeforeSuite
    public void setupGlobalDriver() throws Exception {
        // 配置Desired Capabilities
        DesiredCapabilities caps = new DesiredCapabilities();
        caps.setCapability("platformName", "Android");
        caps.setCapability("deviceName", "emulator-5554");
        caps.setCapability("appPackage", "com.your.app");
        caps.setCapability("appActivity", ".MainActivity");
        // noReset设为false(首次启动需要登录),如果后续要保留状态可以设为true
        caps.setCapability("noReset", false);

        // 初始化Driver,建立会话
        driver = new AndroidDriver<>(new URL("http://127.0.0.1:4723/wd/hub"), caps);
    }

    @Test(priority = 1)
    public void testLoginFlow() {
        // 执行登录操作
        driver.findElement(By.id("com.your.app:id/et_username")).sendKeys("test_user");
        driver.findElement(By.id("com.your.app:id/et_password")).sendKeys("test_pass");
        driver.findElement(By.id("com.your.app:id/btn_login")).click();

        // 等待登录完成,进入主页面
        WebDriverWait wait = new WebDriverWait(driver, 10);
        wait.until(ExpectedConditions.presenceOfElementLocated(By.id("com.your.app:id/main_container")));
    }

    @Test(priority = 2)
    public void testBusinessOperations() {
        // 直接复用全局Driver,此时应用处于登录后的状态
        driver.findElement(By.id("com.your.app:id/btn_my_profile")).click();
        // 继续执行业务流程测试,比如查看个人信息、提交表单等
    }

    @AfterSuite
    public void teardownGlobalDriver() {
        // 所有测试完成后,再关闭Driver和应用
        if (driver != null) {
            driver.quit();
        }
    }
}

示例2:Pytest(Python)

import pytest
from appium import webdriver

# 定义全局会话级别的fixture,所有测试用例共享
@pytest.fixture(scope="session")
def appium_driver():
    desired_caps = {
        "platformName": "Android",
        "deviceName": "emulator-5554",
        "appPackage": "com.your.app",
        "appActivity": ".MainActivity",
        "noReset": False
    }
    # 初始化Driver
    driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps)
    yield driver
    # 会话结束后关闭Driver
    driver.quit()

def test_login(appium_driver):
    # 登录操作逻辑
    appium_driver.find_element_by_id("com.your.app:id/et_username").send_keys("test_user")
    appium_driver.find_element_by_id("com.your.app:id/et_password").send_keys("test_pass")
    appium_driver.find_element_by_id("com.your.app:id/btn_login").click()
    # 验证登录成功
    appium_driver.implicitly_wait(10)
    assert appium_driver.find_element_by_id("com.your.app:id/main_container").is_displayed()

def test_business_flow(appium_driver):
    # 复用Driver执行后续业务操作
    appium_driver.find_element_by_id("com.your.app:id/btn_my_profile").click()
    # 其他业务测试步骤...

方式二:手动保存会话ID,跨脚本复用

如果你的两个脚本是完全独立的文件(比如两个分开的Python脚本),可以在第一部分脚本结束时保存会话信息,第二部分脚本通过这些信息重新连接到已有的会话,而不是新建会话。

步骤1:第一部分(登录脚本)

from appium import webdriver

desired_caps = {
    "platformName": "Android",
    "deviceName": "emulator-5554",
    "appPackage": "com.your.app",
    "appActivity": ".MainActivity",
    "noReset": False
}

# 初始化Driver并执行登录
driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps)
driver.find_element_by_id("com.your.app:id/et_username").send_keys("test_user")
driver.find_element_by_id("com.your.app:id/et_password").send_keys("test_pass")
driver.find_element_by_id("com.your.app:id/btn_login").click()
driver.implicitly_wait(10)
assert driver.find_element_by_id("com.your.app:id/main_container").is_displayed()

# 保存会话信息到临时文件
session_info = {
    "server_url": driver.command_executor._url,
    "session_id": driver.session_id
}
with open("session_data.txt", "w") as f:
    f.write(f"{session_info['server_url']}\n{session_info['session_id']}")

# 注意:这里绝对不要调用driver.quit()!

步骤2:第二部分(业务脚本)

from appium.webdriver.webdriver import WebDriver

# 读取之前保存的会话信息
with open("session_data.txt", "r") as f:
    server_url = f.readline().strip()
    session_id = f.readline().strip()

# 重新连接到已有的会话
driver = WebDriver(command_executor=server_url, desired_capabilities={})
driver.session_id = session_id

# 现在可以直接操作应用,此时应用处于登录后的状态
driver.find_element_by_id("com.your.app:id/btn_my_profile").click()
# 后续业务测试逻辑...

# 所有操作完成后,再决定是否关闭Driver
# driver.quit()

关键注意事项

  • 绝对不要在第一部分脚本中调用driver.quit(),否则会话会被销毁,应用也会被关闭。
  • 关于noReset和fullReset:
    • noReset=true会让Appium不重置应用数据,适合长期保持登录状态;如果是首次运行需要登录,可设为noReset=false,后续复用会话时保持noReset=true。
    • fullReset必须设为false,否则Appium会重新安装应用,之前的状态会丢失。
  • 确保Appium服务器在整个测试过程中持续运行,不要重启服务器,否则所有会话都会失效。

内容的提问来源于stack exchange,提问作者Dtg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:28:20