Appium 并发测试基于unitest
前言:
在回归测试阶段,UI测试,兼容测试是测试的必要步骤。UI自动化的本身是比较冗余的测试,但是换个角度思考,UI自动化同时连接多台设备,那么在回归测试时,在同一个脚本下产生的测试结果是非常有价值的。
不同设备在并发下的测试结果可以为我们提供:
1. 兼容性测试(不同的手机品牌,Android版本, 分辨率等)
2. 性能测试(通过安装Emmagee,监控不同手机在同脚本下,性能的变化)
3. 界面对比(通过图像识别opencv,截图对比等 查看在相同页面的变化)
思路:
1. 启动多路appium服务
2. 启动并连接多路手机端
3. 运行并生成测试报告
问题:
1. python的unittest框架和java不同,不支持参数传入,可以通过重写unittest.TestCase的init添加参数
2. appium 通过命令行启动,需要安装非desktop的版本,且最好安装1.9版本appium,1.0我启动不了
框架代码截取:
1. 重写unittest的初始化函数
class ParametrizedCase(unittest.TestCase):
def __init__(self, methodName='runTest', param=None):
super(ParametrizedCase, self).__init__(methodName)
global devices
devices = param @classmethod
def setUpClass(cls):
cls.driver = connect_device(devices) @classmethod
def tearDownClass(cls):
cls.driver.close_app()
cls.driver.quit()
2. 封装启动appium的服务方法:
基于 appium 的启动命令
appium -p -bp -U
封装多线程启动
class AppiumServer:
def __init__(self, kwargs=None):
self.kwargs = kwargs def start_server(self):
"""start the appium server
"""
for i in range(0, len(self.kwargs)):
cmd = "appium --session-override -p %s -bp %s -U %s" % (
self.kwargs[i]["port"], self.kwargs[i]["bport"], self.kwargs[i]["devices"])
print(cmd)
if platform.system() == "Windows": # windows下启动server
t1 = RunServer(cmd)
p = Process(target=t1.start())
p.start()
while True:
print("--------start_win_server-------------")
if self.win_is_runnnig("http://127.0.0.1:" + self.kwargs[i]["port"] + "/wd/hub" + "/status"):
print("-------win_server_ 成功--------------")
break
else:
appium = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=1,
close_fds=True)
while True:
appium_line = appium.stdout.readline().strip().decode()
time.sleep(1)
print("---------start_server----------")
if 'listener started' in appium_line or 'Error: listen' in appium_line:
print("----server_ 成功---")
break def win_is_runnnig(self, url):
"""Determine whether server is running
:return:True or False
"""
response = None
time.sleep(1)
try:
response = urllib.request.urlopen(url, timeout=5) if str(response.getcode()).startswith(""):
return True
else:
return False
except URLError:
return False
except socket.timeout:
return False
finally:
if response:
response.close() def stop_server(self, devices):
sysstr = platform.system() if sysstr == 'Windows':
os.popen("taskkill /f /im node.exe")
else:
for device in devices:
# mac
cmd = "lsof -i :{0}".format(device["port"])
plist = os.popen(cmd).readlines()
plisttmp = plist[1].split(" ")
plists = plisttmp[1].split(" ")
# print plists[0]
os.popen("kill -9 {0}".format(plists[0])) class RunServer(threading.Thread):
def __init__(self, cmd):
threading.Thread.__init__(self)
self.cmd = cmd def run(self):
os.system(self.cmd)
3. 封装连接Android设备的方法:
def connect_device(devices):
desired_caps = {}
desired_caps['platformVersion'] = devices["platformVersion"]
desired_caps['platformName'] = devices["platformName"]
desired_caps["automationName"] = devices['automationName']
desired_caps['deviceName'] = devices["deviceName"]
desired_caps["appPackage"] = devices["appPackage"]
desired_caps["appActivity"] = devices["appActivity"]
desired_caps["noReset"] = True
desired_caps['noSign'] = True
desired_caps["unicodeKeyboard"] = True
desired_caps["resetKeyboard"] = True
desired_caps["systemPort"] = devices["systemPort"] # desired_caps['app'] = devices["app"]
remote = "http://127.0.0.1:" + str(devices["port"]) + "/wd/hub"
# remote = "http://127.0.0.1:" + "4723" + "/wd/hub"
driver = webdriver.Remote(remote, desired_caps)
return driver
4. 多线程启动服务和多线程连接多终端,生成日志报告
def runnerPool(getDevices):
devices_Pool = [] for i in range(0, len(getDevices)):
_initApp = {}
_initApp["deviceName"] = getDevices[i]["devices"]
_initApp["platformVersion"] = getPhoneInfo(devices=_initApp["deviceName"])["release"]
_initApp["platformName"] = "Android"
_initApp["port"] = getDevices[i]["port"]
_initApp["automationName"] = "UiAutomator2"
_initApp["systemPort"] = getDevices[i]["systemPort"]
_initApp["appPackage"] = 'cn.vsx.vc'
_initApp["appActivity"] = '.activity.RegistActivity'
devices_Pool.append(_initApp)
print(f'devices pool are {devices_Pool}')
with ProcessPoolExecutor(len(devices_Pool)) as pool:
pool.map(runnerCaseApp, devices_Pool) def runnerCaseApp(devices):
suite = unittest.TestSuite()
suite.addTest(ParametrizedCase.parametrize(group_call, param=devices)) # 加入测试类
now = time.strftime('%Y-%m-%d %H_%M_%S')
result = BeautifulReport(suite)
result.report(filename=now + f"_{devices['deviceName'].split(':', 1)[0]}.html", log_path='E:\\TestReports\\',
description=f"{devices['deviceName'].split(':', 1)[0]}") if __name__ == '__main__':
devices = attached_devices()
if len(devices) > 0:
l_devices = []
for dev in devices:
app = {}
app["devices"] = dev
app["port"] = str(random.randint(4700, 4900))
app["bport"] = str(random.randint(4700, 4900))
app["systemPort"] = random.randint(4700, 4900)
l_devices.append(app)
print(f'list of server:{l_devices}')
appium_server = AppiumServer(l_devices)
appium_server.start_server()
runnerPool(l_devices)
appium_server.stop_server(l_devices)
else:
print("没有可用的安卓设备")
以上为大体的运行思路,只截取部分代码,其他的缺失代码可自行思考
思路扩展:
1. unittest框架希望升级成pytest框架更灵活,支持的插件也更多。
2. allure报告支持pytest,更详细美观且可支持Jenkins持续集成
3. 可替换appium为阿里的macaca
(全平台支持,不限制移动端
更专业的 Node 模块开发和封装
驱动更加快速、稳定
本地到持续集成的方案提供
技术栈更新更快
协议更自由 MIT
全面的技术支持
在国内社区更有优势) 当然 appium也不错,实在下载不了就考虑macaca
4. atx uiautomator2 的模式也可以参考,优势在于可通过WiFi进行多手机并发
Appium 并发测试基于unitest的更多相关文章
- appium 并发测试
Android并发测试 Appium提供了在一台设备上启动多个Android会话的方案,而这个方案需要你输入不同的指令来启动多个Appium服务来实现. 启动多个Android会话的重要指令包括: - ...
- Appium 并发多进程基于 Pytest框架
前言: 之前通过重写unittest的初始化方法加入设备参数进行并发,实现了基于unittest的appium多设备并发,但是考虑到unittest的框架实在过于简陋,也不方便后期的Jenkins的持 ...
- Appium+python自动化(三十七)- 士兵突击许三多 - 多个appium服务启动,多个设备启动,多进程并发启动设备-并发测试 - 下(超详解)
简介 接着上一篇继续看一下如何并发测试以及并发测试的过程中,可能遇到的问题,在这里宏哥把宏哥遇到的和小伙伴或者童鞋们,一起分享一下. Appium端口检测 问题思考 经过前面学习,我们已经能够使用py ...
- Appium+python自动化(三十六)- 士兵突击许三多 - 多个appium服务启动,多个设备启动,多进程并发启动设备-并发测试 - 上(超详解)
简介 前面课程只是启动了单个appium服务,只能控制单台设备.如果需要针对多台设备测试那么该如何处理?而且发现群里的小伙伴们也在时不时地在讨论这个问题,想知道怎么实现的,于是宏哥就决定写一片这样的文 ...
- Appium Grid并发测试
背景 Selenium玩的比较6的同学比较清楚:在Selenium中三大组件中有包含了Selenium Grid,而其作用就是分布式执行测试用例.主要的应用场景在于: 缩短测试执行时间,提高自动化测试 ...
- 使用jMeter对基于SAP ID service进行Authentication的Restful API进行并发测试
这篇文章本来Jerry只在SAP社区上写了英文版的,可以通过点击文末的"阅读原文"获得.后来有两位做Marketing Cloud开发的德国同事,写邮件询问关于文章的更多细节,声称 ...
- 使用JMeter3.0实战之分布式并发测试以及web API接口测试
简介: 该文档是以Apche JMeter-3.0为例进行编写的,通过网上的学习资料和官方文档的说明手册学习后,进行项目操作实践,将测试的过程记录下提供给大家学习. 本博文的内容主要是进行配置JMet ...
- 使用CodeBenchmark对逻辑代码进行并发测试
一直对性能测试比较感兴趣,所以也写了不少的测试工具有WebApiBenchmark和TcpBenchmark等;但这些工具测试都是有针对性和配置的方式来进行功能有限所以很难适用更多的场景,所以单独开发 ...
- Atitit.并发测试解决方案(2) -----获取随机数据库记录 随机抽取数据 随机排序 原理and实现
Atitit.并发测试解决方案(2) -----获取随机数据库记录 随机抽取数据 随机排序 1. 应用场景 1 2. 随机抽取数据原理 1 3. 常用的实现方法:::数据库随机函数 1 4. Mssq ...
随机推荐
- Ubuntu 14.04设置开机启动脚本的方法
rc.local脚本 rc.local脚本是一个ubuntu开机后会自动执行的脚本,我们可以在该脚本内添加命令行指令.该脚本位于/etc/路径下,需要root权限才能修改. 该脚本具体格式如下: #! ...
- 安装 mysql5.7.2 (Ubuntu 16.04 desktop amd64)
1.下载mysql deb https://dev.mysql.com/downloads/mysql/ #移动到/usr/local/src/目录,解压 sudo mv mysql-server_5 ...
- c++ 判断容器A是否是容器B的子集,如果是,返回true(includes)
#include <iostream> // cout #include <algorithm> // includes, sort using namespace std; ...
- [ios]sqlite轻量级数据库学习连接
SQLLite (一)基本介绍 http://blog.csdn.net/lyrebing/article/details/8224431 SQLLite (二) :sqlite3_open, sql ...
- Codeforces 385C - Bear and Prime Numbers(素数筛+前缀和+hashing)
385C - Bear and Prime Numbers 思路:记录数组中1-1e7中每个数出现的次数,然后用素数筛看哪些能被素数整除,并加到记录该素数的数组中,然后1-1e7求一遍前缀和. 代码: ...
- 构造函数用return 会出显什么情况
首先我们都知道js中构造函数一般应该是这样的 function Super (a) { this.a = a; } Super.prototype.sayHello = function() { al ...
- LeetCode--155--最小栈
问题描述: 设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈. push(x) -- 将元素 x 推入栈中. pop() -- 删除栈顶的元素. top() -- 获取 ...
- Population Size CodeForces - 416D (贪心,模拟)
大意: 给定$n$元素序列$a$, 求将$a$划分为连续的等差数列, 且划分数尽量小. $a$中的$-1$表示可以替换为任意正整数, 等差数列中必须也都是正整数. 贪心策略就是从前到后尽量添进一个等差 ...
- unittest参数化
我们在写case的时候,如果用例的操作是一样的,就是参数不同,比如说要测一个登陆的接口,要测正常登陆的.黑名单用户登陆的.账号密码错误的等等,在unittest里面就要写多个case来测试. 这样的情 ...
- codefroces 450B矩阵快速幂
找出递推关系式就好了 (fi+1)=(1 -1)(fi ) ( fi)=(1 0)(fi-1) 不会打矩阵将就着看吧... 这是第一道矩阵快速幂.细节还是有很多没注意到的 本来想看挑战写 ...