Appium 3.0:跨平台移动自动化测试框架全面解析

Appium 3.0:跨平台移动自动化测试框架全面解析

项目概述

Appium 是一个开源的跨平台自动化测试框架,基于 WebDriver 协议,为各种移动、桌面和 IoT 平台提供自动化测试能力。Appium 采用模块化和可扩展的架构,支持多种编程语言,拥有完整的驱动和插件生态系统。

核心特性

  • 跨平台支持:支持 iOS、Android、桌面应用等多种平台
  • 多语言支持:提供 Python、Java、JavaScript、Ruby、C# 等客户端库
  • 模块化架构:通过驱动和插件系统实现功能扩展
  • WebDriver 协议:遵循 W3C WebDriver 标准
  • 丰富的生态系统:包含多种官方和第三方驱动、插件
  • 类型安全:完整的 TypeScript 类型定义支持

功能特性

核心功能

  • 原生应用自动化:支持 iOS 和 Android 原生应用的自动化测试
  • 混合应用测试:能够测试包含 WebView 的混合应用
  • 移动 Web 测试:支持移动浏览器中的网页测试
  • 桌面应用自动化:扩展支持桌面应用程序测试
  • IoT 设备支持:为物联网设备提供自动化测试能力

扩展生态系统

  • 驱动系统:为不同平台提供专门的自动化驱动
  • 插件机制:通过插件扩展服务器功能
  • 客户端库:多种编程语言的客户端实现
  • 检查器工具:可视化元素检查和测试录制

安装指南

系统要求

  • Node.js v20.19.0 或更高版本
  • 各平台对应的开发工具(如 Android SDK、Xcode)

安装步骤

  1. 安装 Appium
npm install -g appium
  1. 安装驱动和插件
# 安装 Android 驱动
appium driver install uiautomator2

# 安装 iOS 驱动  
appium driver install xcuitest

# 安装常用插件
appium plugin install images
appium plugin install execute-driver
  1. 验证安装
appium --version
appium driver list
appium plugin list

平台特定说明

  • Android:需要配置 ANDROID_HOME 环境变量
  • iOS:需要安装 Xcode 和开发者工具
  • Windows:可能需要额外配置 .NET 环境

使用说明

基础示例

JavaScript (WebdriverIO)

const {remote} = require('webdriverio');

const capabilities = {
  platformName: 'Android',
  'appium:automationName': 'UiAutomator2',
  'appium:deviceName': 'Android',
  'appium:appPackage': 'com.android.settings',
  'appium:appActivity': '.Settings',
};

async function runTest() {
  const driver = await remote({
    hostname: 'localhost',
    port: 4723,
    capabilities
  });
  
  try {
    const appsItem = await driver.$('//*[@text="Apps"]');
    await appsItem.click();
  } finally {
    await driver.deleteSession();
  }
}

Python

from appium import webdriver
from appium.options.android import UiAutomator2Options

capabilities = dict(
    platformName='Android',
    automationName='uiautomator2',
    deviceName='Android',
    appPackage='com.android.settings',
    appActivity='.Settings'
)

driver = webdriver.Remote('http://localhost:4723', 
                         options=UiAutomator2Options().load_capabilities(capabilities))
el = driver.find_element(by=AppiumBy.XPATH, value='//*[@text="Apps"]')
el.click()
driver.quit()

Ruby

require 'appium_lib_core'

CAPABILITIES = {
  platformName: 'Android',
  automationName: 'uiautomator2',
  deviceName: 'Android',
  appPackage: 'com.android.settings',
  appActivity: '.Settings'
}

core = ::Appium::Core.for capabilities: CAPABILITIES
driver = core.start_driver server_url: 'http://localhost:4723'
driver.wait { |d| d.find_element :xpath, '//*[@text="Apps"]' }.click
driver.quit

服务器配置

通过配置文件或命令行参数配置 Appium 服务器:

// .appiumrc.json
{
  "server": {
    "address": "127.0.0.1",
    "port": 4723,
    "base-path": "/",
    "allow-cors": true,
    "log-level": "info",
    "use-drivers": ["uiautomator2", "xcuitest"],
    "use-plugins": ["images", "execute-driver"]
  }
}

核心代码解析

基础驱动架构

// @appium/base-driver 提供基础驱动类
const {BaseDriver} = require('appium/driver');

class MyCustomDriver extends BaseDriver {
  constructor(opts = {}) {
    super(opts);
    this.desiredCapConstraints = {
      platformName: {
        presence: true,
        isString: true
      },
      app: {
        isString: true
      }
    };
  }

  async createSession(caps, ...args) {
    const [sessionId, customCaps] = await super.createSession(caps, ...args);
    // 自定义会话创建逻辑
    await this.startDevice();
    return [sessionId, customCaps];
  }

  async startDevice() {
    // 启动设备连接
    this.logger.info('Starting device session');
  }
}

插件系统实现

// @appium/base-plugin 提供基础插件类
const {BasePlugin} = require('appium/plugin');

class MyCustomPlugin extends BasePlugin {
  static executeMethodMap = {
    '/session/:sessionId/my_custom_command': {
      POST: {
        command: 'myCustomCommand',
        payloadParams: {required: ['param1']}
      }
    }
  };

  async myCustomCommand(next, driver, sessionId, param1) {
    this.logger.info(`Executing custom command with param: ${param1}`);
    // 自定义插件逻辑
    return {success: true, result: 'Custom command executed'};
  }

  async handle(next, driver, cmdName, ...args) {
    // 拦截和处理命令
    this.logger.info(`Intercepting command: ${cmdName}`);
    const result = await next();
    this.logger.info(`Command ${cmdName} completed`);
    return result;
  }
}

工具函数库

// @appium/support 提供通用工具函数
const {fs, util, logger} = require('appium/support');

class ImageUtils {
  constructor() {
    this.logger = logger.getLogger('ImageUtils');
  }

  async compareImages(image1Path, image2Path) {
    try {
      const image1 = await fs.readFile(image1Path);
      const image2 = await fs.readFile(image2Path);
      
      // 使用 OpenCV 进行图像比较
      const {score} = await getImagesSimilarity(image1, image2);
      this.logger.info(`Image similarity score: ${score}`);
      
      return score > 0.8; // 返回相似度是否超过阈值
    } catch (error) {
      this.logger.error('Image comparison failed:', error);
      throw error;
    }
  }
}

配置管理系统

// @appium/schema 提供配置验证
const {AppiumConfigJsonSchema} = require('@appium/schema');
const ajv = new Ajv();

class ConfigManager {
  constructor() {
    this.validator = ajv.compile(AppiumConfigJsonSchema);
  }

  validateConfig(config) {
    const valid = this.validator(config);
    if (!valid) {
      throw new Error(`Invalid configuration: ${JSON.stringify(this.validator.errors)}`);
    }
    return config;
  }

  async loadConfig(configPath) {
    const configData = await fs.readFile(configPath, 'utf8');
    const config = JSON.parse(configData);
    return this.validateConfig(config);
  }
}

测试支持框架

// @appium/driver-test-support 提供测试工具
const {driverE2ETestSuite, TEST_HOST, getTestPort} = require('@appium/driver-test-support');

describe('MyDriver E2E Tests', function() {
  const capabilities = {
    platformName: 'MyPlatform',
    'appium:automationName': 'MyDriver',
    'appium:app': 'test.app'
  };

  driverE2ETestSuite(MyDriver, capabilities, {
    host: TEST_HOST,
    port: async () => await getTestPort()
  });

  it('should handle custom commands', async function() {
    const result = await this.driver.executeScript('myCustomScript', []);
    expect(result).to.have.property('success', true);
  });
});

这些核心代码展示了 Appium 的模块化架构和扩展性设计,为开发自定义驱动和插件提供了坚实的基础框架。
更多精彩内容 请关注我的个人公众号 公众号(办公AI智能小助手)
对网络安全、黑客技术感兴趣的朋友可以关注我的安全公众号(网络安全技术点滴分享)

公众号二维码

公众号二维码

posted @ 2025-10-19 21:32  qife  阅读(27)  评论(0)    收藏  举报