参考的连接安装sdk+模拟器+appium的教程:
APP自动化知识点详解,基于Java语言(1)APP自动化的环境搭建 - 筱筱创 - 博客园
定位方法的学习参考:
做完元素定位的工作后,要把weditor关闭、要把模拟器重启、appium重启、才可以进行testng的测试。这是最稳的方式。
范过以下错误:
1、获取到元素后,忘记写.click。导致后面的代码都报找不到元素的错误
2、并不是每一个子页面的这个返回元素的id都是一样的"<",自己以为是一样的,结果运行到中间时又报错。
3、
adb pull /sdcard/a.txt D:\apks_for_test
adb push d:/apks_for_test/a.txt /sdcard/
adb logcat >d:\apks_for_test\log.txt
adb shell input tap 100,130------点当前屏幕的这个点
adb shell dumpsys activity | find "mFocusedActivity"可以获取当面页面的包名和类名,获取这个可以用于在app中的任意页面跳转任意页面。
获取到的结果如下:net.duohuo.magapp.LD0766e就是包名 .MainTabActivity就是类名
mFocusedActivity: ActivityRecord{fc7810f u0 net.duohuo.magapp.LD0766e/.MainTabActivity t11}
adb remount----删除系统要用这个命令重新挂载一下,才可以删除成功,系统级别的文件需要
重启后才可以看到已卸载成功的。
genymotion模拟器的下载安装
----------------以下是genymotion模拟器的下载安装操作,但比较麻烦,且对在ARM架构下编译出来的apk好像好多都装不了,所以最后改用“夜神模拟器”------------
可以下载自带虚拟器的genymotion.
其实genymotion就是一个控制安装了安卓系统的虚拟机的终端
或用最新的(我是下载最新的且带有virtaulBox的,安装的时候会安装这两个软件的)
导入ova系统镜像文件
第一次的genymotion的报错如下:
genymotion failed to configure virtualbox host-only interface
要输入账号和密码
指定SDK
apk拖过去安装报这种错的处理方式:
下载安卓系统
-------------------------genymotion内容结束------------------------------------------
夜神模拟器安装:
从官网下载安装。安装完成后配置环境变量,地址为:D:\software\夜神模拟器\Nox\bin。
下面需要保证安卓SDK和夜神模拟器的adb版本保持一致:
查看本地的安卓SDK中的adb版本,如果跟夜神模拟器的nox_adb不一致,就把夜神的nox_adb.exe替换掉(复制,重命名,粘贴–覆盖)。
软件安装很简单有三种方式:
(1)拖拽
(2) 自带的应用市场安装
(3)命令行安装
首先进入安装模拟器的文件夹中,是一个Nox的文件夹中
然后将下载好的apk文件拷贝到该文件夹中
最后运行
安装appium
加插一张图来说明一下服务端和客户端
配置要控制哪一台虚拟机的哪一个程序
{ "deviceName": "127.0.0.1:62025", "platformName": "Android", "appPackage": "net.duohuo.magapp.LD0766e", "appActivity": "net.duohuo.magapp.LD0766e.activity.StartActivity" }
用aapt.exe获取到包名和程序的入口类
这个命令要在aapt.exe所在的目录的路径下用cmd执行
aapt dump badging D:\apks_for_test\saiwangtong1019_sign.apk
这个是appium自带的元素定位工具
这个是sdk下的一个元素定位工具
如何连接真实手机
app界面元素
日志分析定位问题:三种常见的异常
ANR(无响应)
找对应包名的cup使用率可以排除并不是cup过高引起的ANR:
发生ANR之后的cup也没查出什么,因为上面的无响应时我们点了“确定”
cup中找不到问题,则从trace.txt中查看分析
用java编写脚本
确保模拟器是已开机状态、appium是已启动的状态下就可以运行以下的main方法了。
运行main时一边查看appium日志的变化,同是模拟器画面的变化。
元素常用定位方式
常用的事件操作
用自己定义的:(其实也是4.x中的实现)
放大/缩小
新版本的已失效,如果想用,则改为4.1.2版本,把实现copy,再回到新版本定义方法,再粘贴。
直接执行adb命令:
Hybrid/web/Native定位
这个工具不好用的,因为要连接外国网络,常常会慢或连接不上的
用这个uc-devtools这个工具来做
考虑可能是版本的问题(最后结果不是的):
------------------------------------------------------------------------------
--------------------------------------------------------------------
增加切换到iframe,才成功定位元素赋值
别人的Hybrid做的app如何调试
别人的app有内嵌web页面的元素定位,别人的app一般webview debug一般都是关的,所以怎么处理呢,看如下做法:
关掉模拟器,再重新启动模拟器,找到xposed Installer,点击
再关掉模拟器,再重新启动模拟器,这样就可以测试定位(定位内嵌页面元素)别人开发的且有内嵌web页面的app了,且不用联系这个app的开发人员在app的源代码把webview的调试模式打开了( webview.setWebContentsDebuggingEnabled(true))
小程序的自动化测试
九宫格解锁
特殊元素定位之toast
-------------------------------------
通用滑动方法
---------------------
weditor定位元素
1、如果pip的版本太低了,就要升级一下:python -m pip install --upgrade pip
2、pip install Uiautomator2
3、python -m uiautomator2 init 当发现模拟手机中没有安装ATX,则需要执行这个命令进行进行安装,如果安装不成功则需要手动先删除缓存如下图。再执行一次命令3
如果在第一部模拟手机中用weditor定位成功,现在又创建一台新的模拟手机,则只要执行第3条命令在新的模拟手机中安装好ATX,(因之前就装好了weditor)直接python -m weditor 启动就可以了。
4、pip install --user weditor -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
5、weditor --help 确认是否成功安装
6、开启模拟机
7、python -m weditor 启动它
8、访问http://localhost:17310
9、注意:我试过在夜神模拟64位的android7,在weditor显示出来的屏幕画面是黑色的(基本上是无法做,所以我就用32位的了)
组合多属性进行定位
引入日志
<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
log4j.properties内容如下:
### 设置:log4j.rootLogger = [ level ] , appenderName1, appenderName2, …### ###最终各输出点的内容的级别是这个level与具体输出点的Threshold的level的交集### ###all、debug、info、warn、error、fatal、off### log4j.rootLogger = INFO,console,D,E ### 输出信息到控制抬 ### log4j.appender.console = org.apache.log4j.ConsoleAppender log4j.appender.console.Target = System.out log4j.appender.console.layout = org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} %l%m%n log4j.appender.D = org.apache.log4j.DailyRollingFileAppender log4j.appender.D.File = target/app_auto.log log4j.appender.D.Append = true log4j.appender.D.layout = org.apache.log4j.PatternLayout log4j.appender.D.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} %l%m%n log4j.appender.E = org.apache.log4j.DailyRollingFileAppender log4j.appender.E.File =target/app_auto_error.log log4j.appender.E.Append = true log4j.appender.E.layout = org.apache.log4j.PatternLayout log4j.appender.E.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} %l%m%n
reportng生成报告
1、
<!--引入reportng--> <dependency> <groupId>org.uncommons</groupId> <artifactId>reportng</artifactId> <version>1.1.4</version> <scope>test</scope> </dependency> <dependency> <groupId>com.google.inject</groupId> <artifactId>guice</artifactId> <version>3.0</version> </dependency>
2、
reportng-1.1.4.jar用自己改造过的替换掉(详情这一篇博客:reportNG定制化之失败截图)
3、创建CustomListener.java
public class CustomListener extends TestListenerAdapter { /** * 失败时经过这个方法 * @param tr */ @Override public void onTestFailure(ITestResult tr) { String baseDir = "test-output"; String screenshotDir = "screenshot"; String testNameDir = tr.getTestContext().getCurrentXmlTest().getName(); Date date = new Date(); String dateformat = DateFormatUtils.format(date, "yyyy-MM-dd"); String fileName = date.getTime() + ".jpg"; //指定生成图片的路径名称如:test-output/screenshot/xx/2021-10-26/xxx.jpg String filePath=baseDir+ File.separator+ screenshotDir+File.separator+ testNameDir+File.separator+ dateformat+File.separator+fileName; File file = ScreenshotUtil.saveScreenshot(filePath); //D:\apks_for_test\app_auto\test-output\ String toBeReplaced = tr.getTestContext().getCurrentXmlTest().getParameter("tomcatWebapps"); //http://localhost:8080/ String replaceMent = tr.getTestContext().getCurrentXmlTest().getParameter("host"); //D:\apks_for_test\app_auto\test-output\screenshot\xx\2021-10-26\xxx.jpg----->改为---- // http://localhost:8080/screenshot\xx\2021-10-26\xxx.jpg String imgString=getImgString(file,toBeReplaced,replaceMent); Reporter.log(imgString); } private String getImgString(File file,String toBeReplaced,String replaceMent) { String absolutePath = file.getAbsolutePath(); String accessPath = absolutePath.replace(toBeReplaced, replaceMent).replace("\\","/"); String img="<img src='"+accessPath+"' height='100' width='100'><a href='"+accessPath+"' target='_blank'>点击看大图</a></img>"; return img; } }
4、ScreenshotUtil.java
public class ScreenshotUtil { public static File saveScreenshot(String filePath) { File screentshot=Base.androidDriver.getScreenshotAs(OutputType.FILE); File destFile = new File(filePath); try { FileUtils.copyFile(screentshot,destFile); } catch (IOException e) { e.printStackTrace(); } return destFile; } }
5、testng.xml
<parameter name="tomcatWebapps" value="D:\apks_for_test\app_auto\test-output\"/> <parameter name="host" value="http://localhost:8080/"/> <!--配置监听器--> <listeners> <!--实现一个监听器,监听用例执行情况--> <listener class-name="phone_app_auto.report.CustomListener"/> <!--reportng报表生成类--> <listener class-name="org.uncommons.reportng.HTMLReporter"></listener> </listeners>
重试机制
public class TestngRetry implements IRetryAnalyzer { private Logger logger= Logger.getLogger(TestngRetry.class); private int maxRetryCount=2; private int retryCount=1; /** * 当testng.xml中所执行的方法失败的时候会执行retry方法 * @param result * @return */ @Override public boolean retry(ITestResult result) { logger.info("进入retry方法"); if(retryCount<=maxRetryCount){ logger.info("开始第"+retryCount+"次重试,测试方法为:"+result.getName()); retryCount++; return true; } return false; } }
第一种:
//加了这个属性retryAnalyzer,则表示这个方法是有失败重试机制的 @Test(priority = 2,retryAnalyzer = TestngRetry.class) public void testMainPageShow() throws InterruptedException { logger.info("-----------开始点相亲"); // Thread.sleep(3000); click("主页","相亲"); logger.info("-----------进入到相亲页面"); Thread.sleep(3000); }
第二种:
public class RetryListener implements IAnnotationTransformer { @Override public void transform(ITestAnnotation iTestAnnotation, Class aClass, Constructor constructor, Method method) { IRetryAnalyzer retryAnalyzer = iTestAnnotation.getRetryAnalyzer(); //如果用例方法@Test没有定义retryAnalyzer = xxx.class,则会为Null,则会在这里设置重试; // 如果不为空,则会以@Test定义retryAnalyzer来执行重试。 if(retryAnalyzer==null){ iTestAnnotation.setRetryAnalyzer(TestngRetry.class); } } }
然后在testng.xml中加入
<listener class-name="phone_app_auto.listener.RetryListener"></listener>
关于重试机制设置会导致多次截图的问题
testng6.10以上不会有多次截图的问题,tsetng6.10之前的就会有这个问题,且需要自己手动增加if判断等处理。
我用testng6.10测试的时候并不会造成多次截图(我也没有自己特别去处理这事),比如方法1和方法2都设置了3次重试机制,方法1会在才后一次重试失败后才会进行截图,方法2也是一样的。
6.11版本或之前,重试机制结合dataprovider时,会有重试机制不生效的bug的解决方案。
重试机制的应用场景:
1、比如想做登录失败的断言时,可能提示的toast如“密码或用户名不对”的获取会不稳定,这个提示可能一下就消失了,第一次获取不到,这时就需要用重试机制了。
2、还有一些网络原因或手机本身的系统运行问题导致失败的时候,也可以用重试机制。
并发测试
上图是装好appium-desktop就会有的了。
C:\Users\Administrator\AppData\Local\Programs\Appium\resources\app\node_modules\appium\build\lib
运行(是可以运行成功的):
node main.js -a 127.0.0.1 -p 4723 -bp 4724
--------------------------------------node安装的方式------------------------
使用cnpm进行安装
# 安装appium最新版本 cnpm install -g appium --registry=https://registry.npm.taobao.org # 选择版本号安装 cnpm install appium@版本号
# 卸载appium npm uninstall -g appium
查看appium版本
appium -v
启动:cmd直接输入appium
-----------------------------------------------------------------------------------------
开第一台
开第二台
Monkey
Monkey压力测试的原理
1. adb shell monkey的运行机制实际上是执行手机中/system/bin/monkey这个脚本
Monkey压力测试的原理
1. adb shell monkey的运行机制
实际上是执行手机中/system/bin/monkey这个脚本
adb shell monkey -v 500 >F:/monkeylog2018.txt -P表示包名 -V表示输出日志的详细级别 一个-V表示一级 递增 >输出日志的目录
adb shell monkey -p com.htc.Weather –s 10 100 -s 10 前后两条命令相同,那么其随机的内容也是相同的,这样可以在对比测试的时候用到
命令:adb shell monkey -p 包名 –s seed值 执行次数
如果seed值相同,则两次Monkey测试所产生的事件序列也相同的,示例:
测试1:adb shell monkey -p com.kugou.android –s 1540475754297 100
测试2:adb shell monkey -p com.kugou.android –s 1540475754297 100
adb shell monkey -p com.huawei.Weather –throttle 3000 100 每次操作都延迟3秒 随机事件100次 这样可以给app留有响应时间,连网时间,加载时间
--ignore-crashes adb shell monkey -p com.huawei.Weather --ignore-crashes 1000 忽略事件 可以忽略崩溃测试过程中即使程序崩溃,Monkey依然会继续发送事件直到事件数目达到1000为止
--ignore-timeouts adb shell monkey -p com.huawei.Weather --ignore-timeouts 1000 忽略超时 如果程序发生anr超时错误 仍然继续运行
--ignore-security-exceptions adb shell monkey -p com.huawei.Weather --ignore-security-exceptions 1000 即使应用程序发生许可错误,Monkey依然会发送事件,直到事件计数完成
--kill-process-after-error 发生错误后直接杀掉进程:用于指定当应用程序发生错误时,是否停止其运行。如果指定此参数,当应用程序发生错误时,应用程序停止运行并保持在当前状态(注意:应用程序仅是静止在发生错误时的状态,系统并不会结束该应用程序的进程
--monitor-native-crashes adb shell monkey -p com.huawei.Weather --kill-process-after-error --monitor-native-crashes 1000 跟踪本地方法崩溃问题:用于指定是否监视并报告应用程序发生崩溃的本地代码,
指定事件百分比:
用于指定每种类别事件的数目百分比(在Monkey事件序列中,该类事件数目占总事件数目的百分比),虽然事件是随机的,但是你可以指定其中某种动作的比例,根据app的特点而进行设置,某些app滑动多,某些app点击多,这样可以更贴近app应用场景的设置随机事件进行测试
--pct-{+事件类别} {+事件类别百分比}:
--pct-touch {+百分比}:触摸事件:adb shell monkey -p com.huawei.Weather --pct-touch 10 1000
--pct-motion {+百分比}:动作事件:adb shell monkey -p com.huawei.Weather --pct-motion10 1000
--pct-trackball {+百分比}:轨迹事件:adb shell monkey -p com.huawei.Weather --pct-trackball 10 1000
--pct-nav {+百分比}:基本导航:adb shell monkey -p com.huawei.Weather --pct-nav 10 1000
--pct-majornav {+百分比}:主要导航:adb shell monkey -p com.huawei.Weather --pct-majornav 10 1000
--pct-syskeys {+百分比}:系统按键:adb shell monkey -p com.huawei.Weather --pct-syskeys 10 1000
--pct-appswitch {+百分比}:启动activity(日志里见过这个switch吧):adb shell monkey -p com.huawei.Weather --pct-appswitch 10 1000
--pct-anyevent {+百分比}:其他事件:
指定单个类型事件的百分比:
adb shell monkey -p com.huawei.Weather --pct -anyevent 20 1000
指定多个类型事件的百分比:
adb shell monkey -p com.huawei.Weather --pct-anyevent 30 --pct-appswitch 30 1000
注意:各事件类型的百分比总数不能超过100%
防止monkey点击状态栏
adb shell settings put global policy_control immersive.full=*
举例:运行monkey三分钟,每条指令间隔一秒,那就算一下三分钟有180秒就是180运行的次数——adb shell monkey -p <包名> --throttle 1000 180 (未选择随机事件等参数,后续自己视情况加入) ;如果没有间隔时间,先运行一万次记录耗时,然后根据耗时在计算除十个小时需要跑的指令条数