python+atx+uiautomator2多设备UI自动化


基于ATX-Server的UI自动化测试框架,可以实现多设备的并行测试,并生成统一的测试报告

前置条件

Android设备需要通过uiautomator2 init 初始化完成,确认可以正常连接 ,或者init 接入atx-server uiautomator版本需 Version: 0.1.3.dev5 及以后

需要依赖的python第三方库 tinydb、uiautomator2、selenium、jinja2、psutil

相关的基础链接如下

小白入门篇:python uiautomator2 的代码示例

浅谈自动化测试工具 python-uiautomator2

atx 安卓集群管理 安装运行及自动化的实践

ATX-uiautomator2 实现 webview 的操作

 

Public:

  • Devices.py 获取atx-server上特定设备(ATX_Server(object))、或config.ini下devices IP列表的在线设备(get_devices())、有线连接电脑的设备自动连接u2(connect_devices())
  • BasePage.py 用于设备的初始化 u2.connect 已经一些公共模块的封装
  • chromedriver.py 和Ports.py 结合使用,启动chromedriver以便实现u2的webview操作(目前还没做到根据设备的chromeversion 启动指定版本的chromedriver)
  • Casestrategy.py 获取指定路径下的testcases
  • Decorator.py 有[*@*testcase](https://testerhome.com/testcase)、[*@*teststep](https://testerhome.com/teststep)这样的装饰器用例执行日志打印、错误后的处理(截图)
  • Report.py 对生成的报告的一些操作,备份Testreport的报告到TestReport_backup下、多设备统一报告的生成、报告的文件夹压缩
  • Test_data.py 在执行测试前的测试数据的生成,会在Plubic下生成data.json,测试执行的时候各个设设备更具自己的serial获取对应的测试数据
  • Drivers.py 设备的获取,初始化准备,测试执行都是在这里完成的
  • RunCases.py 存放测试报告/日志/截图的路径的生成,以及最终通过HTMLTestRunner来执行用例
  • config.ini 一些需要用到的数据,tatx-server地址、测试设备的ip、测试数据等

 

 

app UI自动化我们通常框架设置思想是pom模式。

1.将具体的定位方式参数化,实现关键字驱动

2.面向业务,将各种通用的业务流程封装成 可重复使用的函数

3.log生成

4.报告生成

5.测试数据、ddt等

 

 

我的这个项目流程做法是:

(1)编写基础定位方式封装成关键字

# 基础定位方法封装
import os
import random
import time
import uiautomator2 as u2
from uiautomator2 import UiObjectNotFoundError
import re
from Public.chromedriver import ChromeDriver
from Public.Ports import Ports
from Public.ReportPath import ReportPath


class BasePage(object):
@classmethod
def set_driver(cls, dri):
cls.d = u2.connect(dri)
cls.sess = cls.d.session("com.tcl.tclplus")

def get_driver(self):
return self.d, self.sess

def ClickText(self, text):
"""
点击文本方法操作
"""
self.d(text=text).click()

def ClickResId(self, page):
"""
根据resourceId 进行点击
"""
self.d(resourceId="com.tcl.tclplus:id/" + page).click()

def ExistsResId(self, page):
"""
判断resid 是否存在
"""
return self.d(resourceId="com.tcl.tclplus:id/" + page).exists()

def ExistsText(self, text):
"""判断文本 是否存在"""
return self.d(text=text).exists

def ClickResIdSendKeys(self, *args):
"""
通过ResId 定位并且 输入内容
"""
self.ClickResId(args[0])
self.d.send_keys(args[1])

def GetTextResID(self, page):
"""
根据RESid 来获取文本
"""
return self.d(resourceId="com.tcl.tclplus:id/" + page).get_text()

def GetTextXpath(self, text):
"""
获取文本的xpath
"""
return self.d.xpath(f'//*[@text="{text}"]').get_text()

 

 

(2)# 业务方法封装

# 业务方法封装
# -*- coding: utf-8 -*-
import random
from Public.Decorator import *


class LoginPage(BasePage):

@teststep
def loginApps(self):
self.ClickText("立即登录")
time.sleep(1)
if self.ExistsText("确认"):
# if self.ExistsResId("bt_confirm"):
log.i("存在确认,先输入账号")
number_list = ["13720140001", "13720140002", "13720140004", "13720140005", "13720140006"]
Count = number_list[random.randint(0, 4)]
log.i(f"取到的账号为{Count}")
self.ClickResIdSendKeys("ll_phone", Count)
self.ClickText("确认")
time.sleep(3)
if self.ExistsText("账号密码登录"):
self.ClickText("账号密码登录")
self.ClickResIdSendKeys("et_pwd", '123456wqw')
if not self.ExistsResId("cb_login"):
self.d.press("back")
while True:
self.ClickResId("cb_login")
self.ClickText("登录")
time.sleep(5)
message = self.sess.toast.get_message(wait_timeout=0.5) # 获取页面toast
print(f'获取到的toast为:{message}')
if message == u"请阅读并同意协议":
continue
else:
break
 

 

(3)用例设计并调用

# -*- coding: utf-8 -*-
import unittest
from PageObject.LoginPage import *
from time import sleep


class CreaitPage(unittest.TestCase, BasePage):
@classmethod
@setupclass
def setUpClass(cls):
pass
cls.drivers, cls.sess = BasePage().get_driver()

@classmethod
@teardownclass
def tearDownClass(cls):
pass

@testcase
def test_001_TCL(self):
"""会员权益入口-当前成长值"""
try:
if self.ExistsText("同意并进入"):
self.ClickText("同意并进入")
self.back()
LoginPage().loginApps()
LoginPage().Eor()
sleep(2)
self.ClickResId("tab_lottie_5")
self.assertEqual("绑定设备可提升成长值", self.GetTextResID("tv_right_copy"))
# self.assertEqual("0", self.GetTextResID("tv_score"))
self.assertEqual("成长值", self.GetTextResID("tv_growth_value"))
log.i("会员权益入口校验成功")
except Exception as e:
raise log.i("会员权益入口校验失败")
finally:
pass

@testcase
def test_002_TCL(self):
"""
会员权益-默认展示当前等级
"""
try:
self.ClickResId("iv_vip_enter")
time.sleep(5)
self.assertEqual("会员中心", self.GetTextResID("toolbar_title"))
log.i("会员权益")
except Exception as e:
raise log.i("会员权益")
finally:
pass


其中里面的设备读取 初始化是之前别人已经封装好的,我们直接拿来用就行。我们只需要做好 基础的定位方式封装成关键字 和面向业务 封装成函数即可。。

网上git项目地址是:http://testerhome.com/topics/21379


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM