ATX基于ATX-Server2的UI自动化测试框架

前言

基于ATX-Server2的UI自动化测试框架,支持多设备的并行测试,并生成统一的测试报告

支持atx-server2

android:修改config下的Server地址为atx-server2的Url,token填写正确后,就可以正常运行了

atxserver2设备管理平台搭建

前置条件

部署好atxserver2
只支持Python 3上运行 本人python版本 3.7
Android设备需要通过uiautomator2 init 初始化完成(python -m uiautomator2 init),确认可以正常连接

工程介绍

工程目录如下

Directory

common:

  • devices.py 获取atx-server2上特定设备(get_atxserver2_online_devices())、或config.ini下devices IP列表的在线设备(get_local_devices())、有线连接电脑的设备自动连接u2(get_usb_devices())
  • atxserver.py 获取
  • base_page.py 用于设备的初始化 u2.connect 已经一些公共模块的封装
  • chromedriver.py 和Ports.py 结合使用,启动chromedriver以便实现u2的webview操作(目前还没做到根据设备的chromeversion 启动指定版本的chromedriver)
  • cases_trategy.py 组织测试用例
  • decorator.py 有@testcase@teststep这样的装饰器用例执行日志打印、错误后的处理、生成截图(支持gif测试步骤)
  • report.py 对生成的报告的一些操作,备份Testreport的报告到TestReport_History下、多设备统一报告的生成、报告的文件夹压缩
  • test_data.py 在执行测试前的测试数据的生成,会在common下生成data.json,测试执行的时候各个设设备更具自己的serial获取对应的测试数据
  • drivers.py 设备的获取,初始化准备,测试执行都是在这里完成的
  • run_case.py 存放测试报告/日志/截图的路径的生成,以及最终通过HTMLTestRunner来执行用例
  • config.ini 一些需要用到的数据,atx-server地址、测试设备的ip、测试数据等

流程:

通过runAll .py开始执行测试

1
2
3
4
5
if __name__ == '__main__':
cs = CaseStrategy()
cases = cs.set_case_suite()
Drivers().run(cases)
zip_report()
  1. ​ 通过CaseStrategy获取到需要执的测试用例
  2. Drivers().run(cases)开始执行测试
  3. ​ 执行完成之后打包压缩(压缩后发邮件方便)

Drivers().run(cases)执行测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
def run(self, cases):
start_time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
devices = check_devices()
if not devices:
print('没有发现设备,测试结束')
return

# generate test data data.json 准备测试数据
generate_test_data(devices)

print('Starting Run test >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
# devices_list = []
# for i in range(len(devices)):
# devices_list.append(RunCases(devices[i]))
run_devices_list = [RunCases(device) for device in devices]

# run on every device 开始执行测试
pool = Pool(processes=len(run_devices_list))
for run_device in run_devices_list:
pool.apply_async(self._run_cases,
args=(run_device, cases,))
print('Waiting for all runs done........ ')
pool.close()
pool.join()
print('All runs done........ ')
# ChromeDriver.kill()

# Generate statistics report 生成统计测试报告 将所有设备的报告在一个HTML中展示
create_statistics_report(run_devices_list)
backup_report('./TestReport', './TestReport_History', start_time)
```
```python
def check_devices():
# 根据method 获取android设备
method = ReadConfig().get_method().strip()
if method == 'SERVER2':
print('atxserver2 中获取可用的在线设备…')
devices = get_atxserver2_online_devices(Atxserver2(ReadConfig().get_server_url()).present_android_devices())
print('atxserver2中有%s台在线设备' % len(devices))

elif method == 'UDID':
print('Get available UDID devices %s from atxserver2...' % ReadConfig().get_server_udid())
devices = get_atxserver2_online_devices(Atxserver2(ReadConfig().get_server_url()).present_udid_devices())
print('\nThere has %s available udid devices in atxserver2' % len(devices))

elif method == 'IP':
# get devices from config devices list
print('Get available IP devices %s from config... ' % ReadConfig().get_devices_ip())
devices = get_local_devices()
print('\nThere has %s devices alive in config IP list' % len(devices))

elif method == 'USB':
# get devices connected PC with USB
print('Get available USB devices connected on PC... ')
devices = get_usb_devices()
print('\nThere has %s USB devices alive ' % len(devices))

else:
raise Exception('Config.ini method illegal:method =%s' % method)

return devices
```
```python
def _run_cases(run_device, cases):
log = Log()
log.set_logger(run_device.get_device()['model'], os.path.join(run_device.get_path(), 'client.log'))
log.i('udid: %s' % run_device.get_device()['udid'])

# 设置cls.path, 必须在操作任何页面之前调用
path = ReportPath()
path.set_path(run_device.get_path())

# 设置cls.driver, 必须在操作任何页面之前调用
base_page = BasePage()
if 'ip' in run_device.get_device():
base_page.set_driver(run_device.get_device()['ip'])
else:
base_page.set_driver(run_device.get_device()['serial'])

try:
# run cases
base_page.set_fastinput_ime() # 切换成FastInputIME输入法
base_page.d.shell('logcat -c') # 清空logcat

run_device.run_cases(cases) # RunCases().run(cases)
# 将logcat文件上传到报告
base_page.d.shell('logcat -d > /sdcard/logcat.log')
time.sleep(1)
base_page.d.pull('/sdcard/logcat.log', os.path.join(path.get_path(), 'logcat.log'))
base_page.set_original_ime() # 切换成正常输入法

if ReadConfig().get_method().strip() in ["UDID", "SERVER2"]:
log.i('释放设备 %s ' % run_device.get_device()['serial'])
Atxserver2(ReadConfig().get_server_url()).release_device(run_device.get_device()['serial'])
else:
pass
except AssertionError as e:
log.e('AssertionError, %s', e)
  1. ​首先根据config.ini中method的值来判断从SERVER2获取online的设备 还是从config.ini中的ip来获取在线的设备
  2. ​在获取到设备之后,根据设备生产data.json测试数据
  3. ​生成设备列表
  4. 根据设备列表数生成多进程,执行测试用例
  5. ​测试完之后,杀掉执行过程
  6. ​最后在TestReport下生成统计测试报告,并且移到TestReport_History下(自动化测试报告.html

结果展示

生成的测试报告路径结构如下
TestReport

每个设备的测试结果及报告或存放在单独的文件夹下
在Testreport目录下会有一个统计测试报告(自动化测试报告.html)会将所有设备的报告统一在一个页面展示
Report