python+appium自动化测试,appium自动化测试环境搭建

  python+appium自动化测试,appium自动化测试环境搭建

  本文主要介绍python和Appium移动多设备自动化测试框架的实现。基于pytest和Appium框架,支持Android和iOS功能自动化测试框架的相关内容。有需要的朋友可以参考一下。

  00-1010前言:1。流程图2。应用服务3。连接测试设备4。元件封装5。操作

  

目录

  本文主要介绍一个基于pytest和Appium框架的测试框架,支持Android和iOS功能自动化。同时,框架支持多设备测试,使用allure库生成可视化测试报告。这个框架主要包括python3、pytest、appium、allure等。这里假设你有相应的基础知识和可以随时运行的测试环境(iOS设备的测试只能在Mac系统下进行,没有Mac的朋友可以看看没有)

  

前言:

  这一部分首先介绍自动化测试的整个过程。目的是在你开始实现框架之前,把测试过程搞清楚,这样我们就可以确定在实现过程中的任何时候都不会被搞糊涂或者不知所措。让我们知道从哪里开始,如何优化和扩展。

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

  以上是本文介绍的框架的核心流程图。上图已经展示了框架的核心流程,所以在下面的叙述中,可以参考这个图进行理解和优化。

  

一、流程图

  在开始我们的测试之前,还有很多工作需要我们去处理,其中最重要的就是启动appium的本地服务。关于appium的实现原理,本文不做过多解释,边肖会花时间补充。到时候希望大家能及时关注。着急的朋友也可以自己百度一下~下面就说说如何启动服务。

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

  /usr/local/bin/appium -a ip -p端口

  也就是说,当我们启动appium时,我们指定ip和端口。一般来说本地ip可以用127.0.0.1,官方默认端口是4723。我们也可以将其修改为我们想要的端口,只要我们确保使用的端口不被其他服务占用。(提示:如果不知道自己的appium安装路径,可以通过哪个appium帮你找到)

  服务启动后,一般我们可以通过访问这个连接来验证服务是否正常:http://127 . 0 . 0 . 1:4723/wd/hub/status。当json格式数据可以正常访问和返回时,服务已经正常启动。

  但事实上,并不是每个创业公司都能一帆风顺,总会出现一些意想不到的情况。例如,端口被占用。在这种情况下,我们不必惊慌,只要做好工作就好。所以今天我们就把上面的流程和python结合起来实现一下。

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

  代码片段如下:

  导入子流程

  导入abc

  导入插座

  类别驱动程序:

  __元类__=abc。ABCMeta

  自我。_host=127.0.0.1

  @abc.abstractmethod

  def connect_appium(自身,端口,n)

  用于连接待实施的设备的方法

  返回

  def start_appium(自身,端口):

  server=self . get _ local _ server _ path()

  主机=readConfig。ReadConfig()。get_commend(host )

  log_path=root_path /result/log

  cmd=%s -a %s -p %s %(服务器,主机,str(端口))

  if self . check _ port(int(port)):

  子流程。Popen(cmd,shell=True,stdout=open( % s/AppiumServer % s . log %(log _ path,port), w ))

  log.lo

  gger.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自动化内容请搜索盛行IT软件开发工作室以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT软件开发工作室!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • android自动化测试框架有哪些,ios手机自动化测试工具,Android和iOS 测试五个最好的开源自动化工具
  • ,,如何使用IOS自动化测试工具UIAutomation
  • android自动化测试框架有哪些,ios手机自动化测试工具
  • ,,Python自动化测试框架pytest的详解安装与运行
  • ,,python自动化测试之DDT数据驱动的实现代码
  • selenium+java自动化测试框架,selenium自动化测试pdf
  • java自动化测试框架,java 自动化测试工具
  • 接口自动化测试面试问题,关于接口测试面试题
  • 自动化测试工具可以用在哪种测试过程中,测试自动化工具有哪些
  • airtest和appium自动化测试,airtest全自动脚本
  • 测试自动化面试问题及答案,自动化测试面试题及答案大全(3)
  • 自动化测试框架是什么,什么叫自动化测试框架
  • python+selenium自动化测试框架搭建,selenium自动化测试环境搭建
  • 接口测试与接口自动化测试,接口自动化测试项目实战
  • appium自动化测试环境搭建,python appium自动化测试框架
  • 留言与评论(共有 条评论)
       
    验证码: