UI自动化测试框架 ATX-Test学习及实践记录
项目说明
本项目fork了github项目ATX-Test,并根据实际测试业务所需做了部分修改。此处对原项目文档进行部分搬运,并对做过修改的部分进行说明。对作者的付出表示深深敬仰与感谢!
原项目基于ATX-Server的UI自动化测试框架,可以实现多设备的并行测试,并生成统一的测试报告。测试用例执行部分基于unittest。
运行方法
-
android:修改TestSuite_*下的config下的Server地址为atx-server2的URL,token填写正确后,就可以正常运行了。
-
ios:在设备接入到atx-server2之后, 可以参照demo下的wda_demo.py可以运行简单的网易云音乐的脚本操作。(ios版本受限于设备原因,并没有尝试过)
项目工程结构
工程结构如图所示

-
apk - 用于存放apk文件
-
chromedriver - 用于存放Chromedriver文件
-
demo - 原工程的demo,删除不影响功能
-
Image - 原工程展示用的Image文件,删除不影响功能
-
Monkey - maxim_monkey模块内容,这块功能还不是很清楚
-
mydemo - 存放单个调试用的demo,删除不影响功能
-
PageObject_* - 存放对应工程的页面对象,PO模式的核心。在该目录存放各页面PO元素的操作后,即可在测试用例中直接调用,大大降低用例编写及修改难度,节约重复编码时间。如图所示为物业城市的PageObject。
-
Public - 通用的主要逻辑控制文件
-
TestSuite_* - 用于存放对应工程的测试套件。如图所示为物业城市测试环境的测试套件。测试套件必须以TestSuite_开头,unittest将据此获取测试用例。
-
.gitignore - git的忽略文件,此文件记录了不列入git管理的文件
-
git git自动生成的文件
-
README.md - 原项目的Readme说明文档
-
run_all_case.by - 运行该项目内所有用例
模块说明
主要功能模块 Public

-
Devices_new.py - 获取atx-server上特定设备(get_online_devices())、或config.ini下devices IP列表的在线设备(get_devices())、有线连接电脑的设备自动连接u2(connect_devices())
-
BasePage.py - 用于设备的初始化 u2.connect 以及一些公共模块的封装
-
chromedriver.py - 和Ports.py 结合使用,启动chromedriver以便实现u2的- webview操作
-
Casestrategy.py - 获取指定路径下的testcases
-
Decorator.py - 有@testcase、@teststep这样的装饰器用例执行日志打印、错误后的处理(截图)
-
Report.py - 对生成的报告的一些操作,备份Testreport的报告到TestReport_backup下、多设备统一报告的生成、报告的文件夹压缩、报告保留数量管理
-
Test_data.py - 在执行测试前的测试数据的生成,会在Plubic下生成data.json,测试执行的时候各个设设备更具自己的serial获取对应的测试数据
-
Drivers.py - 设备的获取,初始化准备,测试执行都是在这里完成的
-
RunCases.py - 存放测试报告/日志/截图的路径的生成,以及最终通过HTMLTestRunner来执行用例
-
config.ini - 一些需要用到的数据,atx-server地址、测试设备的ip、测试数据等。此文件在此工程Public中已被删除,放到各测试用例套件TestSuite里,以分别支持不同测试项目的不同设置。 -
Readconfig - 读取各测试套件的config.ini文件
页面对象模块 PageObject_*

此模块用于存储编写的各测试项目的PageObject。
如图所示的是作为示例的两个PageObject文件login.py和Home.py,分别存储了登录页的PageObject和主页的PageObject。当用例中有需要用到该页元素时可以直接从此调用该元素的点击操作,不需要再重新做一次检查元素Xpath步骤。
PageObject完备时用例编写会变得十分方便快捷,用例编写人员只需要调用相应点击操作函数即可轻松完成一个用例编写,并且当页面元素Xpath发生改变时也可以在此处快速地修改而不影响用例,即PO模式。
每个测试项目可以有一个自己专有的PageObject_*目录。相关的测试项目也可以使用同一个,例如测试环境的项目和生产环境的项目,它们分别使用不同的测试套件和测试用例,但可以共用PageObject。
项目测试套件模块 TestSuite_*

TestSuite_*是某个测试项目的测试套件。里面包含了测试操作集action,测试用例集TestCase,报告目录TestReport_History,项目配置文件config.ini,测试用例运行入口runcase.py。
action
测试操作集。存放了测试的具体操作,用以支持不同的测试用例调用。


TestCase
测试用例目录。
- 测试用例文件需以test_开头,unittest模块才可读取并运行。
- 用例按照数字字母序加载,而不是按照写入顺序。
- 测试用例目录下也可以再新增目录进行测试用例集的划分。如图所示根据不同用户视角划分了几个用例集,用例集内的用例文件以功能来划分,例如安装,登录,登出等。
![]()
如图所示,测试用例文件内函数通过识别不同装饰器执行一些操作。

-
@setUpClass 装饰器为测试类的setup装饰器,将在每个测试用例类执行前执行一次,可以用于进行测试前置操作。
-
@teardownclass 装饰器为测试类的teardown装饰器,将在每个测试用例类执行后执行一次,可以用于进行测试收尾操作。
-
@testcase 装饰器用于标识测试用例函数。被标识的函数会被当做一个测试用例运行。
-
@unittest.skip 装饰器是unittest自带的装饰器,用于标识需要跳过的测试用例,被标识的测试用例不会执行。
除此之外还有很多其他可用的装饰器,包括原工程在Public.Decorator中封装的以及unittest自带的装饰器,需要使用时可以自己查一下。
TestReport_History
用于储存测试报告。每次运行将生成一份包含各设备测试结果的测试报告,测试报告超过一定数量时将自动删除最早的,默认保留10个。测试报告保留数量可以在config.ini里修改。
config.ini
一些需要用到的数据,atx-server地址、测试设备的ip、测试数据等。
- method只能选择一种,不能混用。例如不能同时获取分别使用USB与IP方式连接的设备。

- 测试数据使用“|”做分隔,需要注意每一格的数据与设备一一对应。如图所示例子,第一台设备数据即为以“|”分隔的第一列数据。


runcase.py
该测试套件的测试用例运行入口。
用例结构
用例结构从上到下为用例套件部分TestSuite -> 用例执行的动作action -> 页面实际操作PageObject
关于WebView
测试WebApp有时无法通过直接定位并操作原生控件来完成测试,此时就需要操作WebView来直接在Web页面上进行定位。WebView操作需要依赖于与当前测试手机WebView相同版本的Chromedriver。Webdriver的具体操作在Public -> chromedriver 目录中完成,感兴趣的可以研究一下。
在测试用例中需要用到Webdriver测试时,通过调用如图所示代码来进行Webdriver的设置与回收,并将生成的driver传递给所需的函数/方法。


操作时直接使用生成的selenium.webdriver调用selenium的web元素定位方法定位元素即可,如图所示。

运行流程
1. 通过run_cases .py或者run_all_cases.py开始执行测试
if __name__ == '__main__':
# back up old report dir 备份旧的测试报告文件夹到TestReport_backup下
backup_report()
cs = CaseStrategy()
cases = cs.collect_cases(suite=False)
Drivers().run(cases)
# Generate zip_report file 压缩测试报告文件
# zip_report()
- 首先会将Testreport目录剪切到TestReport_backup目录下,备份旧的测试报告
- 通过CaseStrategy获取到需要执行的测试用例
- Drivers().run(cases)开始执行测试
2. run(cases)执行测试
def run(self, cases):
# 根据method 获取android设备
method = ReadConfig().get_method().strip()
if method == 'SERVER':
# get ATX-Server Online devices
# devices = ATX_Server(ReadConfig().get_server_url()).online_devices()
print('Checking available online devices from ATX-Server...')
devices = get_online_devices()
print('\nThere has %s online devices in ATX-Server' % len(devices))
elif method == 'IP':
# get devices from config devices list
print('Checking available IP devices from config... ')
devices = get_devices()
print('\nThere has %s devices alive in config IP list' % len(devices))
elif method == 'USB':
# get devices connected PC with USB
print('Checking available USB devices connected on PC... ')
devices = connect_devices()
print('\nThere has %s USB devices alive ' % len(devices))
else:
raise Exception('Config.ini method illegal:method =%s' % method)
if not devices:
print('There is no device found,test over.')
return
# generate test data data.json 准备测试数据
generate_test_data(devices)
print('Starting Run test >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
runs = []
for i in range(len(devices)):
runs.append(RunCases(devices[i]))
# run on every device 开始执行测试
pool = Pool(processes=len(runs))
for run in runs:
pool.apply_async(self._run_cases,
args=(run, cases,))
print('Waiting for all runs done........ ')
pool.close()
pool.join()
print('All runs done........ ')
ChromeDriver.kill()
# Generate statistics report 生成统计测试报告 将所有设备的报告在一个HTML中展示
create_statistics_report(runs)
- 首先根据config.ini中method的值来判断从atx-serve获取online的设备 还是从config.ini中的ip来获取在线的设备
- 在获取到设备之后,根据设备生产data.json测试数据
- 并行多设备执行测试
- 测试完之后,杀掉执行过程中打开的所有的chromedriver进程
- 最后在TestReport下生成统计测试报告(自动化测试报告.html)
结果展示
生成的测试报告路径结构如下

每个设备的测试结果及报告或存放在单独的文件夹下
在TestReport_History目录下会有一个统计测试报告(自动化测试报告.html)会将所有设备的报告统一在一个页面展示
报告展示:(此报告展示直接用了gitHub上ATX-Test的图)



浙公网安备 33010602011771号