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

Appium/Webdriverio测试套件:阻止Driver关闭、调整Capabilities及结构优化

解决Appium+WebdriverIO+Mocha测试中不同用例间appium:noReset配置冲突的问题

1. 阻止Driver在测试用例间关闭(共享Session)

WebdriverIO默认会为每个测试文件启动新的Driver Session,导致配置被重置。要实现Session共享,可通过以下方式操作:

  • 修改WDIO核心配置:在wdio.conf.ts中禁用自动启动Driver,同时通过全局钩子维护单个Session:

    // wdio.conf.ts
    export const config: WebdriverIO.Config = {
      autoLaunch: false, // 禁止自动启动默认Session
      maxInstances: 1, // 限制实例数为1,确保单Session运行
      services: [
        ['appium', {
          keepAlive: true, // 保持Appium服务不随Session关闭而终止
        }]
      ],
      // 全局钩子:所有测试执行前启动一次Driver
      beforeSession: async (config, capabilities) => {
        global.driver = await remote({
          ...config,
          capabilities: {
            ...capabilities,
            // 基础Cap配置,后续用例复用该Session
          }
        });
      },
      // 全局钩子:所有测试结束后统一关闭Driver
      afterSession: async () => {
        await global.driver.deleteSession();
      }
    };
    
  • 调整测试文件逻辑:每个测试文件不再单独初始化Driver,直接使用全局driver,并按需重置应用:

    // login.ts
    describe('全新安装登录测试', () => {
      before(async () => {
        // 手动重置应用,模拟全新安装效果
        await global.driver.executeScript('mobile: resetApp');
      });
    
      it('验证首次安装登录流程', async () => {
        // 登录测试逻辑
      });
    });
    
    // doActionAfterLogin_A.ts
    describe('登录后操作测试', () => {
      it('验证登录后的功能A', async () => {
        // 直接使用已登录的Session执行测试
      });
    });
    

    注意:这种方式依赖测试执行顺序,需在WDIO配置的specs数组中指定先执行login.ts再执行doActionAfterLogin_A.ts。

2. 在测试用例间修改Desired Capabilities(独立Session)

Appium的Capabilities是Session启动时确定的,无法在已启动的Session中修改,因此可为每个测试文件单独启动带有对应Cap的Session:

  • 禁用WDIO自动启动:在wdio.conf.ts中设置autoLaunch: false。

  • 每个测试文件手动初始化Driver:

    // login.ts
    import { remote } from 'webdriverio';
    
    describe('全新安装登录测试', () => {
      let driver: WebdriverIO.Browser;
    
      before(async () => {
        driver = await remote({
          hostname: 'localhost',
          port: 4723,
          path: '/wd/hub',
          capabilities: {
            platformName: 'Android',
            'appium:deviceName': 'emulator-5554',
            'appium:app': './path/to/app.apk',
            'appium:noReset': false,
            // 其他必要Capabilities
          }
        });
      });
    
      after(async () => {
        await driver.deleteSession();
      });
    
      it('验证首次安装登录', async () => {
        // 测试逻辑
      });
    });
    
    // doActionAfterLogin_A.ts
    import { remote } from 'webdriverio';
    
    describe('登录后操作测试', () => {
      let driver: WebdriverIO.Browser;
    
      before(async () => {
        driver = await remote({
          hostname: 'localhost',
          port: 4723,
          path: '/wd/hub',
          capabilities: {
            platformName: 'Android',
            'appium:deviceName': 'emulator-5554',
            'appium:app': './path/to/app.apk',
            'appium:noReset': true,
            // 其他必要Capabilities
          }
        });
      });
    
      after(async () => {
        await driver.deleteSession();
      });
    
      it('验证登录后功能A', async () => {
        // 测试逻辑(此时应用保留之前的登录状态)
      });
    });
    

    这种方式每个测试文件完全独立,无需依赖执行顺序,但会增加Session启动的时间开销。

3. 测试用例结构优化建议

当前用例结构存在耦合性高的问题:doActionAfterLogin_A.ts依赖login.ts的执行结果,若登录测试失败,后续测试也会失败,不符合测试用例独立性原则。可调整为以下两种结构:

方案A:将登录作为前置步骤嵌入功能测试

把登录逻辑封装成公共方法,在doActionAfterLogin_A.ts的before钩子中执行,无需单独拆分登录测试文件:

// doActionAfterLogin_A.ts
import { remote } from 'webdriverio';
import { login } from '../utils/login'; // 封装的通用登录方法

describe('登录后功能A测试', () => {
  let driver: WebdriverIO.Browser;

  before(async () => {
    driver = await remote({
      capabilities: {
        'appium:noReset': false, // 每次测试都用全新安装
        // 其他Cap配置
      }
    });
    await login(driver, 'testuser', 'password'); // 执行登录流程
  });

  after(async () => {
    await driver.deleteSession();
  });

  it('验证功能A', async () => {
    // 功能测试逻辑
  });
});

这种方式保证了每个测试用例的独立性,无需切换noReset配置。

方案B:使用持久化登录状态

若需避免重复执行登录流程,可在登录测试完成后,通过Appium API修改应用的持久化存储保存登录状态,后续测试用例直接读取状态并跳过登录:

// login.ts中保存登录状态(Android示例)
after(async () => {
  await driver.executeScript('mobile: shell', {
    command: 'am broadcast -a com.example.app.SAVE_LOGIN --es token "test-auth-token"'
  });
});

// doActionAfterLogin_A.ts中读取状态并跳转到目标页面
before(async () => {
  const token = await driver.executeScript('mobile: shell', {
    command: 'am broadcast -a com.example.app.GET_LOGIN'
  });
  if (token) {
    // 直接跳转到登录后的主页
    await driver.startActivity('com.example.app', '.MainActivity');
  } else {
    // 执行登录流程
    await login(driver);
  }
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 15:05:25