python和Appium移动端多设备自动化测试框架实现

目录
  • 前言:
  • 一、流程图
  • 二、appium服务
  • 三、连接测试设备
  • 四、元素封装
  • 五、运行

前言:

本篇文章主要介绍基于pytest和Appium框架,支持Android和iOS功能自动化的测试框架。同时该框架支持多设备测试,并利用allure库,生成可视化测试报告。本框架主要涉及的内容包括:python3、pytest、appium、allure等,此处已假设你具备相应的基础知识,同时已有可以随时运行的测试环境(iOS设备的测试只能在Mac系统中执行,没有Mac的朋友们,可以看看不执行)

一、流程图

本部分内容先从自动化测试的整体流程开始介绍,目的是希望大家在开始动手去实现框架之前,对测试过程做到清晰明了,这样在实现过程中,才能帮助我们无论何时,都不会迷茫和不知所措。才能让我们知道从何开始,如何优化以及拓展。

那么我们先来看下面这张流程图: 

以上是本文所介绍框架的核心流程图,上图已经展现了框架的核心流程,所以在接下来的讲述中,大家可以参考该图进行理解和优化。

二、appium服务

在开始我们的测试之前,还有很多的工作需要我们去处理,这其中最重要,也是我们开始的第一步,就是开启appium的本地服务。关于appium的实现原理,本文不作过多的讲解,小编会抽空进行补充,届时也希望大家能及时关注。心急的小伙伴也可以自行百度哦~这里仅介绍启动服务的方法。

根据appium官方的介绍,我们可以通过下面的方式来启动appium服务:

/usr/local/bin/appium -a ip -p port

也就是我们在启动appium时,指定ip和端口,一般来说,本地ip使用127.0.0.1即可,官方默认端口为4723,我们也可以修改成自己想要的端口,只要保证使用的端口没有被其他服务占用即可。(小技巧:如果你不知道自己appium安装路径,可通过which appium来帮你找到)

启动服务之后,一般我们可以通过访问这个连接来验证服务是否正常:http://127.0.0.1:4723/wd/hub/status。可正常访问并返回json格式数据时,则说明服务已正常启动。

但事实上,并不是每次启动都可以顺利进行,总会有一些意外的情况发生。比如说端口被占用。遇到这种情况我们也不必惊慌,做好应对即可。那么今天我们就上述的过程结合python,把它实现出来。

上面的过程,用python来实现,其实很简单,我们这里选择使用python中的subprocess库来执行命令,从而达到我们预期。

代码片段如下:

import subprocess
import abc
import socket
class Driver:
	__metaclass__ = abc.ABCMeta
	self._host = '127.0.0.1'
	@abc.abstractmethod
	def connect_appium(self, port, n)
		"""
		待实现的连接设备方法
		"""
		return
	def start_appium(self, port):
		server = self.get_local_server_path()
        host = readConfig.ReadConfig().get_commend("host")
        log_path = root_path + '/result/log'
        cmd = "%s -a %s -p %s" % (server, host, str(port))
        if self.check_port(int(port)):
            subprocess.Popen(cmd, shell=True, stdout=open('%s/AppiumServer%s.log' % (log_path, port), 'w'))
            log.logger.info('%s/AppiumServer%s.log' % (log_path, port))
        else:
            log.logger.info("关闭被占用的端口号:%s" % str(port))
            self.kill_appium()
            log.logger.info("端口释放完毕!启动Appium-server,端口号:%s" % str(port))
            subprocess.Popen(cmd, shell=True, stdout=open('%s/AppiumServer%s.log' % (log_path, port), 'w'))
            log.logger.info("Appium日志信息存储地址: %s/AppiumServer%s.log" % (log_path, port))
    def check_port(self, port):
        """
        检查端口占用情况
        :param port:
        :return:
        """
        try:
            host = local_read_config.get_commend("host")
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            log.logger.info(s.connect((host, port)))
            s.shutdown(2)
        except OSError:
            log.logger.info("端口:%s 可用" % str(port))
            return True
        else:
            log.logger.info("端口:%s 已被占用" % str(port))
            return False

以上代码,会在启动appium服务之前,通过socket检查本地端口是否被占用,若被占用,则先释放端口,然后再启动服务,否则直接启动服务。

至此,服务启动完成,接下来就可以开始连接测试设备。

三、连接测试设备

当我们启动好appium服务后,就可以开始链接测试设备了。因为我们要同时支持Android和iOS的设备,所以我们先来定义一个Driver类,用来封装一些共有属性及方法,然后让Android和iOS分别继承它。

appium对于设备的连接,官方给我们提供了详细的方法事例:

# Android environment
from appium import webdriver
desired_caps = dict(
    platformName='Android',
    platformVersion='10',
    automationName='uiautomator2',
    deviceName='Android Emulator',
    app=PATH('../../../apps/selendroid-test-app.apk')
)
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
el = self.driver.find_element_by_accessibility_id('item')
el.click()
# iOS environment
from appium import webdriver
desired_caps = dict(
    platformName='iOS',
    platformVersion='13.4',
    automationName='xcuitest',
    deviceName='iPhone Simulator',
    app=PATH('../../apps/UICatalog.app.zip')
)
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
el = self.driver.find_element_by_accessibility_id('item')
el.click()

在以上两个示例中,我们发现,链接设备使用的都是同一个方法,但不同的设备需要传入不同的参数,

下面便是链接的关键: 

driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)

既然我们找到了共性,那么就可以对该部分内容进行一番改造,让它来自动完成一些它可以完成的事情。那么首先,我们来看一下,再链接设备的过程中,我们到底做了些什么。

从上面的代码不难看出,每台设备连接都可以看成两步:第一步配置连接参数、第二步请求连接。

那么我们就可以封装一些类和方法,来完成我们想要分端操作的想法了。其实并不困难,我们可以分别写两个类AndroidDriver和IOSDriver,都继承自Driver,然后实现设备连接的方法。

具体实现可参考下面的内容:

from Driver import Driver
class AndroidDriver(Driver):
    def __init__(self):
        self.driver = None

    def get_desired_caps(self):
        """
        实现继承的抽象类方法;获取链接设备的配置信息
        返回设备配置信息
        :return:desired_caps
        """
        desired_list = []
        package = local_read_config.get_value("ANDROID", "package")
        activity = local_read_config.get_value("ANDROID", "activity")
        devices_info = self.update_devices_info()
        for i in range(len(devices_info)):
            udid = devices_info[i].get("udid")
            device_name = devices_info[i].get("devices_name")
            platform_version = devices_info[i].get("version")
            system_port1 = 8200 + 2 * i
            desired_caps = {
                "platformName": "Android",
                "platformVersion": platform_version,
                "appPackage": package,
                "appActivity": activity,
                "deviceName": device_name,
                "automationName": "uiautomator2",
                "udid": udid,
                "systemPort": system_port1,
                "newCommandTimeout": 3000,
                # "adbExecTimeout": 50000
            }
            desired_list.append(desired_caps)
        return desired_list
    def connect_appium(self, port, n):
        """
        根据传入的port,启动appium服务
        :param port:
        :param n:
        :return:
        """
        set_adb_path()
        desired_caps = self.get_desired_caps()
        try:
            self.driver = webdriver.Remote("%s:%s/wd/hub" % (super()._remote_url, str(port)), desired_caps[n])
            return self.driver
        except WebDriverException:
            raise WebDriverException
        except ConnectionError:
            raise ConnectionError

上面的方法主要做了两件事情,首先收集连接设备需要的desired_caps信息,然后是连接设备。需要注意的是,因为我们这个框架是支持多个测试设备同时连接的,所有这里我们把收集到的每台测试设备的desired_caps信息放到了一个数组中,并且在连接设备的时候,我们通过appium服务的端口号和数组下标两个值,来确定,每台测试设备连接的appium服务。

小提示:一个appium服务无法同时连接多个手机,但是我们希望能同时连接多个测试手机,并且同时在这连接的多个手机上进行测试,所以我们这里启动了多个appium服务,并指定了每个启动的服务端口号。因此我们只需要将端口号和设备信息对应上即可。

至此,启动服务和测试设备连接的实现就结束了,接下来就是对元素的操作了。那么我们一起来看一下,关于Element的那些事情。

四、元素封装

众所周知,元素的操作依赖于元素查找。

举个常见的例子:我想百度搜索一个关键词,那么我首先要找到搜索框,才能输入关键词,然后找到搜索按钮,并点击搜索。这就是我们要做的。

常见的定位元素的方法有:ID、XPATH、CLASSNAME、NAME、PREDICATE等,selenium提供了对应的方法,我们这里也不做过多的封装,大家可以直接使用,也可以像我这样,把一些常见的定位方式封装成一个统一的方法,实现如下:

    def get_element(self, element_id):
        """
        获取指定页面的元素路径数据
        :param element_id: 元素ID
        :return: 获取的元素对象
        """
        element_type = self.page.get(element_id).get("pathType")
        element_value = self.page.get(element_id).get("pathValue")
        element = None
        if element_type == "ID":
            element = self.driver.find_element_by_id(element_value)
        elif element_type == "CLASSNAME":
            element = self.driver.find_element_by_class_name(element_value)
        elif element_type == "XPATH":
            element = self.driver.find_element_by_xpath(element_value)
        elif element_type == "NAME":
            element = self.driver.find_element_by_name(element_value)
        elif element_type == "ACB_ID":
            element = self.driver.find_element_by_accessibility_id(element_value)
        elif element_type == "PREDICATE":
            element = self.driver.find_element_by_ios_predicate(element_value)
        return element

大家自己选择是否进行封装,正常调用selenium的方法也是OK哒。

同样的道理,我们还可以封装一些常用的操作,比如滑动屏幕,键盘操作等。

分端元素操作

因为我们分别接入了Android和iOS,那么它们的操作,各有不同之处,我们可以将各自的特色操作分别集中到一个单独的AndroidElement类和iOSElement类中,这样在后面使用的时候,我们直接继承这两个类就可以,并且从结构上看,也比较清晰。

比如同样是滑动屏幕,swipe在Android和iOS系统上的表现就不一致,因此我们就选择了其他方法:

AndroidElement:

    def swipe_to_up(self):
        """
        向上划,页面滚动到最下方
        :return:
        """
        width = self.driver.get_window_size()["width"]
        height = self.driver.get_window_size()["height"]
        self.driver.swipe(width / 2, height * 3 / 5, width / 2, height / 5, duration=500)

iOSElement:

    def swipe_to_up(self):
        """
        向上滑动
        :return:
        """
        self.driver.execute_script('mobile: swipe', {'direction': 'up'})

以上只是一个小例子,只是想说明,如果有这样的操作差异,我们可以将它们分开处理,这样会显得逻辑更清晰。

有了上面的实现,我们就只需要写测试的脚步就可以。写脚本部分的内容就先略过,不做详细描述,毕竟不同的业务需求场景,都有其独特的脚本逻辑。凡事万变不离其宗,元素还是那个元素,操作还是那些操作,就让大家自己去尽情发挥吧。

那么,一切准备就绪,就差让我们的程序跑起来了。接下来就让我们来看看,如何让我们的测试同时在多个连接的测试设备上进行测试。

五、运行

因为我们的测试是通过pytest来执行的,所以pytest的所有执行参数都是可以正常使用的。而我们,也只是利用pytest的main函数来完成本次执行。唯一不同的是,为了满足不同设备同时进行测试,我们为每一台设备的测试,都创建了一个进程。每一个进程都包含了上述完整的流程。选择进程而非线程的原因也很简单,相信大家也都知道,进程和线程的关系吧,在同一个进程中的线程资源是共享的。而在我们看来,每一台设备的测试都应该是独立的、互不干扰的,所以我们选择进程而非线程。

具体实现如下:

from multiprocessing import Process
import pytest
import time
import os, re
import subprocess
from appiums.common import read_files
from appiums.driver.iOSDriver import IOSDriver
from driver.androidDriver import AndroidDriver
from driver import Driver
from elements import Element

class Run(Process):
    def __init__(self, name, args):
        super(Run, self).__init__()
        self.name = name
        self.args = args
        self.root_path = os.getcwd()
        self.device_name = re.sub('[\']', '', str(args[2].get("deviceName")).replace(" ", "_"))
    def run_test(self):
        """
        执行测试用例
        :return:
        """
        pytest.main([
                     '--alluredir', '%s/result/data/%s' % (self.root_path, self.device_name)])
        time.sleep(2)
    def generate_report(self):
        """
        整合测试报告到项目根目录下的result/report目录下
        :return: none
        """
        cmd = "allure generate %s/result/data/%s -o %s/result/report/%s --clean" \
              % (self.root_path, self.device_name, self.root_path, self.device_name)
        stdout = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, text=True)
        log.logger.info("测试报告查看路径:%s" % str(stdout.stdout.readlines()[0]).split(" ")[-1][:-1])
    def get_environment_info(self):
        """
        获取测试环境的信息
        :return:
        """
        env = {
            "测试平台": self.args[2].get("platformName"),
            "设备名称": self.device_name,
            "设备系统版本": self.args[2].get("platformVersion"),
            "设备udid": self.args[2].get("udid"),
            "应用名称": self.args[2].get("bundleId") if str(self.args[2].get("platformName")).lower() == 'ios' else self.args[2].get("appPackage"),
        }
        return env
    def run(self):
        """
        执行线程中的任务
        :return:
        """
        Driver.Driver().start_appium(self.args[0])
        time.sleep(5)
        self.set_driver()
        time.sleep(1)
        self.run_test()
        time.sleep(1)
        read_files.set_environment(self.device_name, self.get_environment_info())
        time.sleep(1)
        self.generate_report()

def main(desired_caps):
    """
    开启测试进程执行测试
    """
    list_p = []
    process_num = len(desired_caps)
    if process_num > 0:
        for a in range(process_num):
            port1 = 4723 + 2 * a
            p = Run('测试进程-%s' % str(port1), args=(port1, a, desired_caps[a]))
            p.start()
            log.logger.info("设备%s在进程 %s 上进行测试, 进程ID:%s" % (desired_caps[a].get("deviceName"), p.name, p.pid))
            list_p.append(p)
        for b in list_p:
            b.join()
        Driver.Driver().kill_appium()
    else:
        log.logger.error("没有设备可进行测试,请重新连接设备后尝试!")
        exit(-1)

def android_run():
    caps = AndroidDriver().get_desired_caps()
    main(caps)

def ios_run():
    caps = IOSDriver().get_desired_caps()
    main(caps)

到此这篇关于python和Appium移动端多设备自动化测试框架实现的文章就介绍到这了,更多相关python和Appium自动化内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Python+Appium实现自动化清理微信僵尸好友的方法

    随着微信的使用时间越长,微信好友也越来越多,有些好友将你删除了你也不知道.当我们发消息的时候会出现下面扎心的一幕,然后默默将他删除 使用 Appium 基础的 appium 使用在公众号文章 <解放双手,提高生产力,这款神器你值得拥有> 中已经讲过了,这里使用最新 1.20.0 版本的 appium,旧版本会出现真机微信闪退的情况 安装一下 Python 用到的模块 pip install Appium-Python-Client 获取好友列表 在 Pycharm 中配置一下启动环境 desi

  • 分享5个方便好用的Python自动化脚本

    目录 1.自动化阅读网页新闻 2.自动生成素描草图 3.自动发送多封邮件 4.自动化数据探索 5.自动桌面提示 前言: 相比大家都听过自动化生产线.自动化办公等词汇,在没有人工干预的情况下,机器可以自己完成各项任务,这大大提升了工作效率. 编程世界里有各种各样的自动化脚本,来完成不同的任务.尤其Python非常适合编写自动化脚本,因为它语法简洁易懂,而且有丰富的第三方工具库.这次我们使用Python来实现几个自动化场景,或许可以用到你的工作中. 1.自动化阅读网页新闻 这个脚本能够实现从网页中抓

  • python+appium自动化测试之如何控制App的启动和退出

    目录 一.启动app 二.退出App 三.appium实现原理 四.如何获取deviceName? 五.如何获取apk的appActivity和appPackage? 由于本人使用的是Android设备做自动化测试,所以以下内容均基于Android系统做出的整理 一.启动app 启动app需要设置Capability参数,而Capability参数放在Desired Capalibity中,Desired Capalibity告诉Appium想要的自动化平台和应用程序,这是一组键值对,主要是用于

  • Python+Selenium自动化环境搭建与操作基础详解

    目录 一.环境搭建 1.python安装 2.pycharm下载安装 3.selenium下载安装 4.浏览器驱动下载安装 二.Selenium简介 (1)SeleniumIDE (2)SeleniumRC (3)SeleniumWebDriver (4)SeleniumGrid 三.常用方法 1.浏览器操作 2.如何获取页面元素 3.查找定位页面元素的方法 4.操作方法 5.下拉框操作 6.WINDOS弹窗 7.iframe内嵌页面处理 8.上传文件 9.切换页面 10.截图 11.等待时间

  • Python+Appium自动化测试的实战

    目录 一.环境准备 二.真机测试 一.环境准备 1.脚本语言:Python3.x IDE:安装Pycharm 2.安装Java JDK .Android SDK 3.adb环境,path添加E:\Software\Android_SDK\platform-tools 4.安装Appium for windows,官网地址http://appium.io/ 点击下载按钮会到GitHub的下载页面,选择对应平台下载 安装完成后,启动Appium,host和port默认的即可,然后设置Android

  • 使用python的turtle库画一个冰墩墩效果

    目录 设置一个画布 画左手和手内 画轮廓和其他部分 画细节(眼睛.鼻子.嘴巴等) 画头部彩虹 画五环标志 使用python画一个冰墩墩先看效果图 设置一个画布 import turtle turtle.setup(800,600) turtle.speed(10) 画左手和手内 turtle.penup() turtle.goto(177,112) turtle.pencolor('lightgray') turtle.pensize(3) turtle.fillcolor('white') t

  • Appium+Python+pytest自动化测试框架的实战

    菜鸟一枚,写的不好勿喷,大家一起学习 先简单介绍一下目录,再贴一些代码,代码里有注释 Basic目录下写的是一些公共的方法,Data目录下写的是测试数据,image存的是测试失败截图,Log日志文件,Page测试的定位元素,report测试报告,Test测试用例,pytest.ini是pytest启动配置文件,requirements.txt需要安装的py模块,run.py运行文件 Basic/base.py 里面封装了 一些方法,元素的点击,输入,查找,还有一些自己需要的公共方法也封装在里面,

  • python+appium实现自动化测试的示例代码

    目录 1.什么是Appium 2.启动一个app自动化程序的步骤 3.appium服务介绍 4. appium客户端使用 5.adb的使用 6.Appium启动过程分析 1.什么是Appium appium是一个开源的测试自动化框架,可以与原生的.混合的和移动的web应用程序一直使用.它使用WebDriver协议驱动IOS(内置的测试引擎xcuitest).Android(uiautomator2,Espresso)和Windows应用程序 原生应用程序:安卓程序是用JAVA或kotlin开发出

  • python和Appium移动端多设备自动化测试框架实现

    目录 前言: 一.流程图 二.appium服务 三.连接测试设备 四.元素封装 五.运行 前言: 本篇文章主要介绍基于pytest和Appium框架,支持Android和iOS功能自动化的测试框架.同时该框架支持多设备测试,并利用allure库,生成可视化测试报告.本框架主要涉及的内容包括:python3.pytest.appium.allure等,此处已假设你具备相应的基础知识,同时已有可以随时运行的测试环境(iOS设备的测试只能在Mac系统中执行,没有Mac的朋友们,可以看看不执行) 一.流

  • python利用Appium实现自动控制移动设备并提取数据功能

    目录 1. 安装appium-python-client模块并启动已安装好的环境 1.1 安装appium-python-client模块 1.2 启动夜神模拟器 1.3 启动appium-desktop 1.4 利用上一小节所学习的内容获取Desired Capabilities参数 2. 初始化以及获取移动设备分辨率 3. 定位元素以及提取文本的方法 3.1 点击appium desktop右上角的放大镜图标 3.2 定位界面的使用方法如下图所示 3.3 点击短视频的作者名字,查看并获取该元

  • Python+unittest+requests 接口自动化测试框架搭建教程

    一.Python+unittest+requests+HTMLTestRunner 完整的接口自动化测试框架搭建_00--框架结构简解 首先配置好开发环境,下载安装Python并下载安装pycharm,在pycharm中创建项目功能目录.如果不会的可以百度Google一下,该内容网上的讲解还是比较多比较全的! 大家可以先简单了解下该项目的目录结构介绍,后面会针对每个文件有详细注解和代码. common: --configDb.py:这个文件主要编写数据库连接池的相关内容,本项目暂未考虑使用数据库

  • python+appium+yaml移动端自动化测试框架实现详解

    结构介绍 之前分享过一篇安卓UI测试,但是没有实现数据与代码分离,后期维护成本较高,所以最近抽空优化了一下. 不想看文章得可以直接去Github,欢迎拍砖 大致结构如下: testyaml管理用例,实现数据与代码分离,一个模块一个文件夹 public 存放公共文件,如读取配置文件.启动appium服务.读取Yaml文件.定义日志格式等 page 存放最小测试用例集,一个模块一个文件夹 results 存放测试报告及失败截图 logs 存放日志 testcase 存放测试用例runtest.py

  • Python使用Appium在移动端抓取微博数据的实现

    目录 使用Appium在移动端抓取微博数据 查找Android App的Package和入口 记录微博刷新动作 爬取微博第一条信息 使用Appium在移动端抓取微博数据 Appium是移动端的自动化测试工具,读者可以类比为PC端的selenium.通过它,我们可以驱动App完成自动化的一系列操作,同样也可以爬取需要的内容. 这里,我们需要首先在PC端安装Appium软件,安装下载的地址如下:https://github.com/appium/appium-desktop/releases 安装软

  • Python与Appium实现手机APP自动化测试的示例代码

    目录 1.什么是Appium 2.启动一个app自动化程序的步骤 3.appium服务介绍 4. appium客户端使用 5.adb的使用 6.Appium启动过程分析 1.什么是Appium appium是一个开源的测试自动化框架,可以与原生的.混合的和移动的web应用程序一直使用.它使用WebDriver协议驱动IOS(内置的测试引擎xcuitest).Android(uiautomator2,Espresso)和Windows应用程序 原生应用程序:安卓程序是用JAVA或kotlin开发出

  • python 基于Appium控制多设备并行执行

    前言: 如何做到,控制多设备并行执行测试用例呢. 思路篇 我们去想下,我们可以获取参数的信息,和设备的信息,那么​我们也可以针对每台设备开启不一样的端口服务.那么每个服务都对应的端口,我们在获取设备列表的时候,要和 每个服务对应起来,这样,我们开启一个进城池,我们在进程池里去控制设备,​每个进程池 控制不一样的设备即可. 实现篇 首先实现对应的参数篇和对应的设备端口, def startdevicesApp():     l_devices_list=[]     port_list=[]   

  • Python3 + Appium + 安卓模拟器实现APP自动化测试并生成测试报告

    2020年4月补充 鉴于配置自动化测试这套框架确实稍微有点麻烦,许多小伙伴在配置的过程中总是踩坑,最近写了篇简化版的入门教程,不想折腾Android SDK的小伙伴可以移步到那篇文章:https://www.jb51.net/article/169763.htm 概述 本文主要分为以下几个部分 安装Python3 安装Python3的Appium库 安装Android SDK 安装JDK 安装Appium 安装模拟器 编写测试脚本并生成测试报告 项目示例下载地址: https://github.

  • Python利用appium实现模拟手机滑动操控的操作

    目录 滑动操控 如何获取设备屏幕坐标系 模拟实现一个简单的滑动操作 将 “滑动操控” 改为公共的方法 其实在前面两个章节的元素定位的场景,我们已经对 app 中的自动化操作已经略知一二.这里我们发现, 实际上 appium 复用了 selenium 的很多很多的操作方式,所以像一些 “点击.输入” 等操作,这种常规的操作的方式与在 WEB 自动化中的方式基本上是完全一致的,就不再进行赘述了. 唯一一个与 WEB 端不太一样的地方就是关于 “滑动操控” ,所以 “页面的滑动” 在实际操作手机过程中

随机推荐