python-appium/README.md

517 lines
22 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 0910 UPDATE
* 新增控件集参数化相同测试步骤的Android/iOS可共用一份测试用例
* 不同测试步骤的用例还需要单独写
## 0904 UPDATE
* 优化Android log及crsahinfo相关输出路径
* 新增iOS crashreport解析
## 新增内容:
* 适配iOS
* 提取android crash信息
* 优化report(增加自动填充包名app名称版本bundleId等信息)
## 简介
采用python3+appium1.8基于PageObject框架的UI自动化测试持续集成。
* unittest参数化
* PageObject分层管理
* 用例编写基于yaml配置多关键字驱动
* 自动生成excel测试报告
* 同时支持Android/iOS
* 支持多设备执行
* 支持Windows/Mac OS iOS必须使用Mac OS
## 目录结构
#### 1.app
```
待测apk/ipa 安装包路径
uiautomator2等安装包路径
```
#### 2.Base
```
Android 测试相关:
BaseAdb.py
BaseAndroidPhone.py
BaseApk.py
BaseLog.py
BaseLogcat.py
iOS 测试相关:
BaseIosPhone.py
BaseIpa.py
BaseIosLog.py
数据处理相关:
BaseConfig.py
BaseExcel.py
BaseFile.py
BasePickle.py
BaseYaml.py
BaseOperate.py
BaseReplace.py
测试执行相关:
BaseAppiumServer.py
BaseInit.py
BaseRunner.py
BaseElements.py
报告相关:
BaseStatisics.py
BaseError.py
BaseEmail.py
```
#### 3. iOSCrashAnalysis
```
iOS crash report  解析相关:
BaseIosCrash.py 解析脚本
FileOperate.py 文件操作相关
symbolicatecrash xCode自带的解析工具获取方式find /Applications/Xcode.app -name symbolicatecrash -type f复制过来就行了
```
#### 4.Log
```
设备日志及持久化数据
操作日志,失败截图
crash解析结果
```
#### 5.PageObject
```
操作的封装及测试结果统计
测试用例模块分级
```
#### 6.其他
```
../Report =====测试报告
../Runner =====执行文件
../TestCase =====测试用例集
../yamls =====用例管理
```
## 主要功能
#### 1.基础测试类及方法
* 获取apk/ipa安装包信息
* 获取Android/iOS设备信息
* 自动分配端口并启动appiumserver
* 设备日志及crashlog分析
* 失败重试
* 失败截图
* 报告统计及输出
* 邮件发送
* case管理
* 常用操作封装
* 其他
#### 2.yaml编写说明
```buildoutcfg
testinfo: 表示用例介绍
- id: 用例id
- title: 用例标题
- info: 前置条件
testcase: 用例的执行步骤
- element_info: //XCUIElementTypeStaticText[@name="剪辑"] 元素
- find_type: id 元素类型
- id
- xpath
- name
- text
- ids 需要增加index
- index 和ids/xpaths/texts等配合
- class_name
- ios_id
- predicate
- operate_type: click 操作
- click
- swipe_down
- swipe_up
- get_value
- set_value
- screen_tap
- swipe_left
- swipe_right
- msg 传给set_value关键字
- adb_tab 使用adb中的tab命令点击元素,元素必须可识别,应用于悬浮层场景
- get_content_desc 无法切换到webview时用此关键字
- press_key_code 键盘触发事件需要传code
- code 传给press_key_code关键字
- is_webview:1 为1表示切换到webview,为2表示切换到原生
- 其他关键字 用于定制一些特殊业务
- is_time: 3 自定义暂停3秒
- info: 点击动态列表第一条数据 操作步骤介绍
- check: 检查点,支持多检查点
- element_info: //XCUIElementTypeStaticText[@name="剪辑"]
- find_type: ids
- index: 0
- operate_type:
- contrary" 相反检查点,表示如果检查元素存在就说明失败,如删除后,此元素依然存在
- contrary_getval 检查点关键字contrary_getval: 相反值检查点,如果对比成功,说明失败
- default_check 默认检查点,就是查找页面元素
- compare 历史数据和实际数据对比
- toast toast检查
- info: 查找是否存在历史记录
```
#### 3.yaml实例
```buildoutcfg
==========================================================
testinfo:
- id: home_test_001
title: 启动app并进入gallery
info: 打开app并点击高级编辑
testcase:
- element_info: camerta_n
find_type: ios_id
operate_type: click 
info: 点击创作中心主按钮
- element_info: //XCUIElementTypeStaticText[@name="剪辑"]
find_type: xpath
operate_type: click
info: 点击剪辑按钮
- element_info: 跳过
find_type: name
operate_type: click
info: 跳过升级页面
- element_info: //XCUIElementTypeStaticText[@name="剪辑"]
find_type: xpath
operate_type: click
info: 点击剪辑按钮
- element_info: 好
find_type: name
operate_type: click
info: 授权存储
- element_info: 好
find_type: name
operate_type: click
info: 授权相册
check:
- element_info: //XCUIElementTypeButton[@name="下一步"]
find_type: xpath
check: default_check
info: 进入'Gallery'页面成功
```
#### 4.某个用例的page层
```buildoutcfg
from PageObject import Pages
class PageOperate:
def __init__(self, kwargs):
_init = {"driver": kwargs["driver"], "test_msg": getYam(kwargs["path"]), "device": kwargs["device"],
"logTest": kwargs["logTest"], "platformName": kwargs["platformName"],"caseName": kwargs["caseName"]}
self.page = Pages.PagesObjects(_init)
def operate(self): # 操作步骤
self.page.operate()
def checkPoint(self): # 检查点
self.page.checkPoint()
```
#### 5.testcase层调用page层
```buildoutcfg
tc_temp = PATH("../yamls/temp.yaml")
el_android = PATH("../yamls/el_android.yaml")
el_iOS = PATH("../yamls/el_iOS.yaml")
class HomeTest(ParametrizedTestCase):
def repalce(self, tc, tc_temp):#用了最笨的替换字符串方法输出一个临时temp.yaml文件测试完成后再删除
if self.platformName == 'android':
ReplaceYaml(tc, tc_temp, el_android)
elif self.platformName == 'iOS':
ReplaceYaml(tc, tc_temp, el_iOS)
def testFirstOpen(self):
tc = PATH("../yamls/home/firstOpen.yaml")
self.repalce(tc, tc_temp)
app = {"logTest": self.logTest, "driver": self.driver, "path": tc_temp,
"device": self.udid, "platformName": self.platformName, "caseName": sys._getframe().f_code.co_name}
page = PageOperate(app)
page.operate()
page.checkPoint()
def testSecondOpen(self):
tc = PATH("../yamls/home/secondOpen.yaml")
self.repalce(tc, tc_temp)
app = {"logTest": self.logTest, "driver": self.driver, "path": tc_temp,
"device": self.udid, "platformName": self.platformName, "caseName": sys._getframe().f_code.co_name}
page = PageOperate(app)
page.operate()
page.checkPoint()
```
#### 6.Case入口
```buildoutcfg
def runnerCaseApp(devices):
starttime = datetime.now()
suite = unittest.TestSuite()
suite.addTest(ParametrizedTestCase.parametrize(HomeTest, param=devices))
# suite.addTest(ParametrizedTestCase.parametrize(HomeTest, param=devices)) #加入测试类
unittest.TextTestRunner(verbosity=2).run(suite)
endtime = datetime.now()
countDate(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), str((endtime - starttime).seconds) + "秒")
```
#### 7.实时日志展示
```buildoutcfg
testFirstOpen (TestCase.HomeTest.HomeTest) ... ==操作步骤com.quvideo.xiaoying:id/xiaoying_alert_dialog_positive_click ==
==操作步骤com.android.packageinstaller:id/permission_allow_button_click ==
==操作步骤com.android.packageinstaller:id/permission_allow_button_click ==
==操作步骤com.quvideo.xiaoying:id/wel_skip_click ==
==操作步骤com.quvideo.xiaoying:id/layout_fragment_creation_click ==
==操作步骤com.quvideo.xiaoying:id/icon1_click ==
==操作步骤text("跳过")_click ==
==操作步骤com.quvideo.xiaoying:id/icon1_click ==
==操作步骤text("其他相册")_ ==
Platform: android
Device: 4ed397ac
==用例_启动app并进入gallery检查点成功==
ok
```
#### 8.操作日志输出展示
```buildoutcfg
2018-08-23 11:51:08,390 - INFO - ---- home_test_001_启动app并进入gallery_com.quvideo.xiaoying:id/xiaoying_alert_dialog_positive_click ----
2018-08-23 11:51:09,711 - INFO - ---- home_test_001_启动app并进入gallery_com.android.packageinstaller:id/permission_allow_button_click ----
2018-08-23 11:51:10,583 - INFO - ---- home_test_001_启动app并进入gallery_com.android.packageinstaller:id/permission_allow_button_click ----
2018-08-23 11:51:19,866 - INFO - ---- home_test_001_启动app并进入gallery_com.quvideo.xiaoying:id/wel_skip_click ----
2018-08-23 11:51:23,644 - INFO - ---- home_test_001_启动app并进入gallery_com.quvideo.xiaoying:id/layout_fragment_creation_click ----
2018-08-23 11:51:29,023 - INFO - ---- home_test_001_启动app并进入gallery_com.quvideo.xiaoying:id/icon1_click ----
2018-08-23 11:51:30,361 - INFO - ---- home_test_001_启动app并进入gallery_text("跳过")_click ----
2018-08-23 11:51:33,660 - INFO - ---- home_test_001_启动app并进入gallery_com.quvideo.xiaoying:id/icon1_click ----
2018-08-23 11:51:35,636 - INFO - ---- home_test_001_启动app并进入gallery_text("其他相册")_ ----
2018-08-23 11:51:35,698 - INFO - [CheckPoint_1]: testFirstOpen_ : OK
2018-08-23 11:51:52,341 - INFO - ---- home_test_002_进入拍摄页面_com.quvideo.xiaoying:id/img_creation_click ----
2018-08-23 11:51:54,148 - INFO - ---- home_test_002_进入拍摄页面_com.quvideo.xiaoying:id/icon2_click ----
2018-08-23 11:51:55,116 - INFO - ---- home_test_002_进入拍摄页面_text("允许")_click ----
2018-08-23 11:51:56,704 - INFO - ---- home_test_002_进入拍摄页面_text("总是允许")_click ----
2018-08-23 11:51:57,834 - INFO - ---- home_test_002_进入拍摄页面_text("总是允许")_click ----
2018-08-23 11:52:01,559 - INFO - ---- home_test_002_进入拍摄页面_text("高清相机")_ ----
2018-08-23 11:52:01,647 - INFO - [CheckPoint_2]: testSecondOpen_ : OK
```
#### 9.crash解析-android
```buildoutcfg
=========================crash================================
06-20 13:41:06.165 7638 7638 E AndroidRuntime: Process: com.quvideo.xiaoying, PID: 7638
06-20 13:41:06.165 7638 7638 E AndroidRuntime: java.lang.NullPointerException: Attempt to read from field 'int com.quvideo.xiaoying.datacenter.social.publish.PublishTaskInfo.step' on a null object reference
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at com.quvideo.xiaoying.app.publish.d.a.aI(SourceFile:67)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at com.quvideo.xiaoying.app.publish.d.a.aK(SourceFile:123)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at com.quvideo.xiaoying.app.publish.d.a.a(SourceFile:151)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at com.quvideo.xiaoying.app.publish.SocialPublishBaseActivity.da(SourceFile:1531)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at com.quvideo.xiaoying.app.publish.SocialPublishBaseActivity.aaM(SourceFile:1565)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at com.quvideo.xiaoying.app.publish.c.b$1.acg(SourceFile:312)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at com.quvideo.xiaoying.videoeditor.j.a.a$4.m(SourceFile:650)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at com.quvideo.xiaoying.ui.dialog.c.onClick(SourceFile:165)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at android.view.View.performClick(View.java:6291)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at android.view.View$PerformClick.run(View.java:24931)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:808)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:101)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at android.os.Looper.loop(Looper.java:166)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:7425)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)
06-20 13:41:06.367 732 732 E wificond: Failed to get NL80211_RATE_INFO_NOISE
06-20 13:41:06.367 732 732 E wificond: Failed to get NL80211_RATE_INFO_SNR
06-20 13:41:06.367 732 732 E wificond: Failed to get NL80211_STA_INFO_CNAHLOAD
06-20 13:41:07.841 1157 1174 I chatty : uid=1000(system) android.ui expire 3 lines
06-20 13:41:07.851 1448 1780 I HwNetworkPolicyManager: getHwUidPolicy uid = 10063 policy = 0
06-20 13:41:07.878 1157 2823 I chatty : uid=1000(system) Binder:1157_F expire 1 line
06-20 13:41:07.879 1157 1350 I chatty : uid=1000(system) ConnectivitySer expire 14 lines
06-20 13:41:07.879 1157 8282 I chatty : uid=1000(system) Binder:1157_1B expire 10 lines
06-20 13:41:07.893 1157 8281 I chatty : uid=1000(system) Binder:1157_1A expire 12 lines
06-20 13:41:07.900 17940 17940 I ActivityThread: Removing dead content provider:android.content.ContentProviderProxy@b3b0cdb
06-20 13:41:07.911 1157 14597 I chatty : uid=1000(system) Binder:1157_1F expire 9 lines
06-20 13:41:07.936 1157 1167 I chatty : uid=1000(system) Binder:1157_1 expire 14 lines
=========================crash=========================
06-20 13:41:06.165 7638 7638 E AndroidRuntime: Process: com.quvideo.xiaoying, PID: 7638
06-20 13:41:06.165 7638 7638 E AndroidRuntime: java.lang.NullPointerException: Attempt to read from field 'int com.quvideo.xiaoying.datacenter.social.publish.PublishTaskInfo.step' on a null object reference
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at com.quvideo.xiaoying.app.publish.d.a.aI(SourceFile:67)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at com.quvideo.xiaoying.app.publish.d.a.aK(SourceFile:123)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at com.quvideo.xiaoying.app.publish.d.a.a(SourceFile:151)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at com.quvideo.xiaoying.app.publish.SocialPublishBaseActivity.da(SourceFile:1531)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at com.quvideo.xiaoying.app.publish.SocialPublishBaseActivity.aaM(SourceFile:1565)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at com.quvideo.xiaoying.app.publish.c.b$1.acg(SourceFile:312)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at com.quvideo.xiaoying.videoeditor.j.a.a$4.m(SourceFile:650)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at com.quvideo.xiaoying.ui.dialog.c.onClick(SourceFile:165)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at android.view.View.performClick(View.java:6291)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at android.view.View$PerformClick.run(View.java:24931)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:808)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:101)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at android.os.Looper.loop(Looper.java:166)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:7425)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
06-20 13:41:06.165 7638 7638 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)
06-20 13:41:06.367 732 732 E wificond: Failed to get NL80211_RATE_INFO_NOISE
06-20 13:41:06.367 732 732 E wificond: Failed to get NL80211_RATE_INFO_SNR
06-20 13:41:06.367 732 732 E wificond: Failed to get NL80211_STA_INFO_CNAHLOAD
06-20 13:41:07.841 1157 1174 I chatty : uid=1000(system) android.ui expire 3 lines
06-20 13:41:07.851 1448 1780 I HwNetworkPolicyManager: getHwUidPolicy uid = 10063 policy = 0
06-20 13:41:07.878 1157 2823 I chatty : uid=1000(system) Binder:1157_F expire 1 line
06-20 13:41:07.879 1157 1350 I chatty : uid=1000(system) ConnectivitySer expire 14 lines
06-20 13:41:07.879 1157 8282 I chatty : uid=1000(system) Binder:1157_1B expire 10 lines
06-20 13:41:07.893 1157 8281 I chatty : uid=1000(system) Binder:1157_1A expire 12 lines
06-20 13:41:07.900 17940 17940 I ActivityThread: Removing dead content provider:android.content.ContentProviderProxy@b3b0cdb
06-20 13:41:07.911 1157 14597 I chatty : uid=1000(system) Binder:1157_1F expire 9 lines
06-20 13:41:07.936 1157 1167 I chatty : uid=1000(system) Binder:1157_1 expire 14 lines
06-20 13:41:07.942 1157 1367 I chatty : uid=1000(system) CallbackHandler expire 2 lines
06-20 13:41:07.958 1157 1182 I chatty : uid=1000(system) android.display expire 1 line
```
#### 10. crash解析-iOS
```buildoutcfg
============开始导出crashreport==========
idevicecrashreport -u 5214866ccb9342f87f4c2aab093c25f7e252fd85 /Users/zhulixin/Desktop/python-appium/Log/CrashInfo/iOS/Before/
Move: WiFi/WiFiManager/wifi-buf-05-23-2018__18:35:55.107.log
Move: WiFi/WiFiManager/wifi-buf-08-12-2018__02:40:07.213.log
Move: WiFi/WiFiManager/wifi-buf-05-06-2018__21:15:54.957.log
Move: WiFi/WiFiManager/wifi-buf-06-19-2018__05:16:04.564.log
Move: WiFi/WiFiManager/wifi-buf-06-16-2018__10:05:31.097.log
Move: WiFi/WiFiManager/wifi-buf-11-04-2017__14:36:48.log
Move: WiFi/WiFiManager/wifi-buf-12-03-2017__14:31:53.log
Move: WiFi/WiFiManager/wifi-buf-11-14-2017__22:41:35.log
Move: WiFi/WiFiManager/wifi-buf-05-13-2018__23:07:34.084.log
Move: WiFi/WiFiManager/wifi-buf-06-19-2018__08:05:54.196.log
Move: WiFi/WiFiManager/wifi-buf-01-23-2018__23:50:53.018.log
Move: WiFi/WiFiManager/wifi-buf-12-03-2017__15:54:45.log
Move: WiFi/WiFiManager/wifi-buf-04-10-2018__14:33:15.105.log
Move: WiFi/WiFiManager/wifi-buf-08-12-2018__20:34:03.165.log
Move: WiFi/WiFiManager/wifi-buf-08-24-2018__02:50:49.140.log
.....
.....
Move: XiaoYing-2018-07-30-114612.ips
Move: XiaoYing-2018-07-30-162434.ips
Move: XiaoYing-2018-07-28-123234.ips
Move: XiaoYing-2018-09-04-102545.ips
Move: XiaoYing-2018-07-31-095526.ips
Move: XiaoYing-2018-07-31-151350.ips
Move: XiaoYing-2018-09-04-102545.ips
Move: XiaoYing-2018-07-30-113126.ips
Move: XiaoYing-2018-07-30-114612.ips
Move: com.apple.appstored/appstored.log
Done.
============开始解析待测app相关crashreport==========
输入的文件为: /Users/zhulixin/Desktop/python-appium/Log/CrashInfo/iOS/Before/XiaoYing-2018-07-30-114612.ips
输出的文件为:
0x100c24000 - 0x102ff3fff XiaoYing arm64 <2deaa9887c173bb0a9f4b051e47f04a3> /var/containers/Bundle/Application/170BDC50-F0D3-4973-9781-D414532E21CD/XiaoYing.app/XiaoYing
2DEAA988-7C17-3BB0-A9F4-B051E47F04A3
'/dSYMs/XiaoYing.app.dSYM'
输入的文件为: /Users/zhulixin/Desktop/python-appium/Log/CrashInfo/iOS/Before/XiaoYing-2018-07-30-162434.ips
输出的文件为:
0x100290000 - 0x10265ffff XiaoYing arm64 <2deaa9887c173bb0a9f4b051e47f04a3> /var/containers/Bundle/Application/C5855F55-13D0-49FE-ADC2-7C82565237D0/XiaoYing.app/XiaoYing
2DEAA988-7C17-3BB0-A9F4-B051E47F04A3
'/dSYMs/XiaoYing.app.dSYM'
......
......
============crashreport解析完成==========
============删除所有解析之前的crash文件==========
/Users/zhulixin/Desktop/python-appium/Log/CrashInfo/iOS/Before/JetsamEvent-2018-09-04-104135.ips was removed!
Directory: /Users/zhulixin/Desktop/python-appium/Log/CrashInfo/iOS/Before/JetsamEvent-2018-09-04-104135.ips was removed!
Directory: /Users/zhulixin/Desktop/python-appium/Log/CrashInfo/iOS/Before/WiFi was removed!
/Users/zhulixin/Desktop/python-appium/Log/CrashInfo/iOS/Before/XiaoYing-2018-07-30-114612.ips was removed!
Directory: /Users/zhulixin/Desktop/python-appium/Log/CrashInfo/iOS/Before/XiaoYing-2018-07-30-114612.ips was removed!
/Users/zhulixin/Desktop/python-appium/Log/CrashInfo/iOS/Before/XiaoYing-2018-07-30-162434.ips was removed!
Directory: /Users/zhulixin/Desktop/python-appium/Log/CrashInfo/iOS/Before/XiaoYing-2018-07-30-162434.ips was removed!
/Users/zhulixin/Desktop/python-appium/Log/CrashInfo/iOS/Before/XiaoYing-2018-09-04-102545.ips was removed!
Directory: /Users/zhulixin/Desktop/python-appium/Log/CrashInfo/iOS/Before/XiaoYing-2018-09-04-102545.ips was removed!
Directory: /Users/zhulixin/Desktop/python-appium/Log/CrashInfo/iOS/Before/com.apple.appstored was removed!
/Users/zhulixin/Desktop/python-appium/Log/CrashInfo/iOS/Before/XiaoYing-2018-07-30-184609.ips was removed!
......
......
Process finished with exit code 0
```
#### 11.最终log输出信息及路径
![](/uploads/photo/2018/ffcbafc0-06ff-4613-84a7-7f32bd70c82d.png!large)
#### 12.报告输出
1.Android
![](/uploads/photo/2018/5d9c8027-a3cb-429e-8d6a-3dee68aa97d1.png!large)
![](/uploads/photo/2018/9754aa6e-19d4-4ed7-a1b8-482a5f2b740c.png!large)
2.iOS
![](/uploads/photo/2018/02ae6200-e724-4d50-9ec9-9b9eb5f901be.png!large)
![](/uploads/photo/2018/9bc957b3-cd10-43c2-b174-e96749a5d884.png!large)
## 运行环境
1. Windows 7及以上 / OSX
2. Android SDK的执行环境
3. python3.x
4. Appium 1.7.x及以上
## 代码获取
最新的稳定代码会推送到github上直接clone即可使用。
```
git@github.com:Lemonzhulixin/python-appium.git
```
## 执行注意事项
1.安装包路径指定Base.BaseInit
```
apkPath = PATH("../app/VivaVideo_7.2.5.apk") # 测试的app路径
ipaPath = PATH("../app/xiaoying.ipa") # 测试的app路径
```
2.为了避免同一台PC上同时连接android和iOS设备时获取设备问题将runner文件两个平台分开处理
```
Android执行: python3 ../Runner/runner.py
iOS执行:python3 ../Runner/runner_iOS.py
```
3.在过滤待测app crashreport时记得在runner_iOS.py中修改待测app crashreport文件关键字
```buildoutcfg
find_str = 'XiaoYing-' # 待测app crashreport文件关键字
```
4.过滤待测app系统日志修改待测app关键字如此处的'XiaoYing'
```buildoutcfg
#获取系统日志过滤当前app的log如不需要获取系统日志注掉即可
syslog_path = os.path.join(PATH("../Log/CrashInfo/iOS/"), "syslog.log")
sys_cmd = 'idevicesyslog -u ' + get_phone["udid"] + " |grep 'XiaoYing' > %s" % (syslog_path)
os.popen(sys_cmd)
```
## 目前的遗留问题
- email邮件发送尚未调试
- 多设备执行还有点问题
- 当遇到有些用例比较麻烦必须单独写page层
- 因为对python的map方法不是很懂所以控件集参数化用了最原始最笨的字符串替换输出一个临时temp.yaml文件测试完成后再删除如果有对map熟悉的同学欢迎帮忙写个方法来处理感谢
## 后续计划
- 测试数据DB存储
- 结果集分析