文档开发者中心
我的

跟测试老兵3天成为APP高手(三)

(十四)安装Python的基础包工具setuptools


一种安装方法:


C:\Users\IBM\AppData\Local\Programs\Python\Python37\Lib\test\libregrtest\setup.py install


另一种是下载安装的exe文件,默认安装Python37\Lib\site-packages下面


(十五)检查安装selenium 和selenium server端


C:\Users\IBM>pip install -U selenium


Requirement already up-to-date: selenium in c:\users\ibm\appdata\local\programs\python\python37\lib\site-packages



提示上面信息,表明已经安装成功。下面绿色字体表示pip版本可以升级。


打开https://code.google.com/p/selenium/下载selenium server服务端。


安装selenium sever,使用java -jar selenium-server-standalone-3.14.0.jar进行安装,安装界面成功后如下图,



查看安装的selenium版本:


C:\Users\IBM>pip show selenium


Name: selenium


Version: 3.14.1


如果安装IE driver,则需要与selenum相同的版本(主版本号相同,小版本号可不同)。


(十六)安装Chrome Driver(如果想学习Web自动化测试的话安装)


https://sites.google.com/a/chromium.org/chromedriver/downloads,下载chrome driver驱动放在chrome安装目录中,目前下载只有32位版本。应该也支持64位,但是有可能有坑。



在环境变量的path中添加上述地址。或者把chromedriver.exe拷贝到与代码相同的路径下。


在python编辑器中,添加下面代码,则可以执行。


from selenium import webdriver


driver =webdriver.Chrome()


driver.get('http://www.baidu.com')


print(driver.title)


driver.quit()


(十七)Appium代码框架解释


public AndroidDriver<?> driver; //驱动程序


private String apkName='proname.apk'; //安卓的安装包,被测软件

private String platformVersion = '4.4.2';//安卓模拟器的版本

private String serverURL = 'http://127.0.0.1:4723/wd/hub';//appium测试服务的地址


File classpathRoot = new File(System.getProperty('user.dir'));//获得项目路径

File appDir = new File(classpathRoot, 'apps');//获得APK所在文件夹名称

File app = new File(appDir, apkName);//获得APK文件


DesiredCapabilities capabilities = new DesiredCapabilities(); /*新建一个DesiredCapabilities对象,是import org.openqa.selenium.remote.DesiredCapabilities;作者个人认为是用来收集驱动初始化信息用的;*/


capabilities.setCapability(CapabilityType.BROWSER_NAME, ''); //指定浏览器的名字,我们测试的是APK所以没有浏览器,故而为空;

capabilities.setCapability('platformName', 'Android'); // 指定平台,为安卓

capabilities.setCapability('deviceName', 'Android Emulator'); //指定设备,'Android Emulator'这个属性作者认为是“安卓设备即可”

capabilities.setCapability('platformVersion', platformVersion); //指定版本,作者的模拟器是4.4.2的

capabilities.setCapability('app', app.getAbsolutePath()); //指定需要测试的APK,也就是需要安装的APK文件;

//核心关键步骤,创建驱动,指定服务地址,和初始化信息


driver = new AndroidDriver (new URL(serverURL),capabilities);


driver.findElementByAccessibilityId('using').click(); //点击操作

driver.findElementByAccessibilityId('using').clear(); //清除操作,一般是有文字的信息的输入框

driver.findElementByAccessibilityId('using').sendKeys('XXYYMM'); //输入操作'XXYYMM'为你要输入的内容

driver.pressKeyCode(Android_KeyCode.KEYCODE_3); //模拟键盘输入

driver.tap(fingers, element, duration); //点击,fingers是几根手指,element是什么元素(WebElement element = driver.findElementByAccessibilityId('using')), //duration为点击时长,处理长按操作,单位是毫秒,1000毫秒=1秒

driver.tap(fingers, x, y, duration); //坐标点击

driver.zoom(el); //放大,el为元素

driver.zoom(x, y); //放大,通过坐标位置

driver.pinch(el); //缩小,el为元素

driver.pinch(x, y); //缩小,通过坐标

driver.swipe(startx, starty, endx, endy, duration); //滑动,从一个点到另一个点,duration为时长,单位是毫秒,1000毫秒=1秒


下面是测试浅言app的代码,解析如下:


package com.mooctest; //代码放在一个Java包中,包的名称可以随意填写,一般是公司名称或网址相关


import org.testng.AssertJUnit;


import io.appium.java_client.AppiumDriver;


import io.appium.java_client.AndroidKeyCode;


import java.io.File;


import java.net.MalformedURLException;


import java.net.URL;


import java.sql.Time;


import java.util.NoSuchElementException;


import java.util.concurrent.TimeUnit;


import org.apache.commons.exec.OS;


import org.openqa.selenium.By;


import org.openqa.selenium.WebElement;


import org.openqa.selenium.remote.DesiredCapabilities;


//通过import引入各种需要的包,包里是我们需要的一些方法


public class Main {


private boolean isInstall =false;


/**


* 'appPackage', 'com.zhy.qianyan'


* 'app-launchActivity', 'com.zhy.qianyan.MainActivity'


* 本示例脚本仅作为参考,具体请根据自己的测试机型可能出现的特殊情况进行脚本的编写调整


*/


/**


* 所有和AppiumDriver相关的操作都必须写在该函数中


* @param driver


*/


public void test(AppiumDriver driver) {


String ret=null;


try {


Thread.sleep(6000); //等待6s,待应用完全启动后,再做后续处理


} catch (InterruptedException e) {


// TODO Auto-generated catch block


e.printStackTrace();


}


driver.manage().timeouts().implicitlyWait(8, TimeUnit.SECONDS); //设置尝试定位控件的最长时间为8s,也就是最多尝试8s


/*


* 余下的测试逻辑请按照题目要求进行编写


*/


try {


Thread.sleep(4000); //等待4s,待应用完全显示完整


} catch (InterruptedException e) {


// TODO Auto-generated catch block


e.printStackTrace();


}


driver.findElement(By.xpath('//android.widget.Button[@resource-id='com.huawei.systemmanager:id/btn_allow']')).click();


try {


Thread.sleep(6000); //等待6s,待操作完成


} catch (InterruptedException e) {


// TODO Auto-generated catch block


e.printStackTrace();


}


//获得屏幕窗口的宽和高


int width = driver.manage().window().getSize().width;


int height = driver.manage().window().getSize().height;


//从屏幕右侧向左侧滑动三次,滑过三个页面


driver.swipe(width*9/10, height/2, width/10, height/2,5000);


driver.swipe(width*9/10, height/2, width/10, height/2,5000);


driver.swipe(width*9/10, height/2, width/10, height/2,5000);


//单击页面中的热点,名称为“开启你的故事”


driver.findElement(By.xpath('//android.widget.TextView[@text='开启你的故事']')).click();


driver.findElement(By.id('android:id/button2')).click(); //单击取消按钮


driver.findElement(By.xpath('//android.view.ViewGroup/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.widget.ImageView[1]')).click();


try {


Thread.sleep(3000); //等待3s,待应用完全显示完整


} catch (InterruptedException e) {


// TODO Auto-generated catch block


e.printStackTrace();


}


driver.swipe(width*2/5, height*6/10, width*2/5, height/10,5000); //为了显示出注册/登录按钮,需要向上滑动


try {


Thread.sleep(3000); //等待3s,待应用完全显示完整


} catch (InterruptedException e) {


// TODO Auto-generated catch block


e.printStackTrace();


}


driver.findElement(By.xpath('//android.widget.TextView[@text='注册/登录']')).click(); //单击登录按钮进入登录界面


//输入用户名和密码


driver.findElementByName('请输入手机号码').sendKeys('13910077365'); driver.findElementByXPath('//android.view.ViewGroup/android.widget.EditText[2]').sendKeys('123456');


driver.findElement(By.xpath('//android.widget.TextView[@text='浅 言']')).click(); //去掉输入法


driver.findElement(By.xpath('//android.widget.TextView[@text='登录']')).click(); //单击登录窗口


try {


Thread.sleep(3000); //等待3s,待应用完全显示完整


} catch (InterruptedException e) {


// TODO Auto-generated catch block


e.printStackTrace();


}


ret = driver.findElement(By.xpath('//android.widget.TextView[@text='个人中心']')).getText(); //获得个人中心这个窗口信息


System.out.println(ret); //打印找到文本


//AssertJUnit.assertEquals('个人中心', driver.findElementByXPath('//android.widget.TextView[@text='个人中心']').getText());


/*


AppiumDriver driver1 = Screenshot.getDriver();


File location = new File('screenshots1');


String screenShotName = location.getAbsolutePath()+File.separator+tr.getMethod().getMethodName()+'.png';


File screenShot = driver.getScreenshotAs(OutputType.FILE);


try{


FileUtils.copyFile(screenShot, new File(screenShotName));


}


catch(IOException e){


e.printStackTrace();


}


*/


if(isElement(driver,By.xpath('//android.widget.TextView[@text='用户名或密码错误!']')))


{


System.out.println('登录失败!');


return;


}


}


/**


* AppiumDriver的初始化逻辑必须写在该函数中


* @return


*/


public AppiumDriver initAppiumTest() {


AppiumDriver driver=null;


File classpathRoot = new File(System.getProperty('user.dir'));


File appDir = new File(classpathRoot, 'apk');


File app = new File(appDir, 'qianyan.apk');


//设置自动化相关参数


DesiredCapabilities capabilities = new DesiredCapabilities();


capabilities.setCapability('browserName', '');


capabilities.setCapability('platformName', 'Android');


//capabilities.setCapability('deviceName', 'Android Emulator');


capabilities.setCapability('platformVersion', '6.0.0');


capabilities.setCapability('deviceName', 'HUAWEI MT7-TL10');


//设置apk路径


capabilities.setCapability('app', app.getAbsolutePath());


//设置app的主包名和主类名


capabilities.setCapability('appPackage', 'com.zhy.qianyan');


capabilities.setCapability('appActivity', '.MainActivity');


//设置使用unicode键盘,支持输入中文和特殊字符


capabilities.setCapability('unicodeKeyboard','true');


//设置用例执行完成后重置键盘


capabilities.setCapability('resetKeyboard','true');


//初始化


try {


driver = new AppiumDriver(new URL('http://127.0.0.1:4723/wd/hub'), capabilities);


} catch (MalformedURLException e) {


// TODO Auto-generated catch block


e.printStackTrace();


}


return driver;


}


public void start() {


test(initAppiumTest());


}


public static void main(String[] args) {


Main main = new Main();


main.start();


}


public boolean isElement(AppiumDriver driver,By locator) {


try {


driver.findElement(locator);


System.out.println('kongjian is appeard!');


return true;


} catch (NoSuchElementException e) {


System.out.println('does not exist!');


return false;


}


}


}


下面是自动化脚本执行过程中的界面。



看到上面有三个tab页面








登录按钮被输入法遮盖,所以需要把输入法隐藏


(十八)Appium-java API详解


目前appium-java最新版本是5.0.0-BETA3,因此就拿最新的说明,以Java为例,首先引入java client的依赖:

<dependency>

<groupId>

io.appium

</groupId>

<artifactId>

java-client

</artifactId>

<version>

5.0.0-BETA3

</version>

</dependency>

API主要分为两类,分别是元素定位类和模拟操作类。

元素定位类findElementByXX


driver.findElementById(“id”);

id获取方法:利用uiautomater截屏,获取resource id;

driver.findElementByClassName(“className”);

通常通过这种方式获取的view不止一个,需要遍历一遍得到的 views,然后根据条件匹配需要的view。

driver.findElementByName(“text”);

name获取方法:利用uiautomater截屏,获取text;

driver.findElementsByLinkText (“text”);

针对webview上元素的超链接

driver.findElementByXPath(“//*[@name=’62’]”);

举例,我要定位下图页面中的这个元素,我采用xpath定位时,可以这样写:

WebElement webElement = driver

.findElementByXPath

(

'//android.widget.TextView[contains(@text,'商品描述')]'

)

;

webElement.click();


查找多元素时,直接用相应的findElementsByXX即可。


模拟操作类


driver.runAppInBackground(5); //将当前活跃的应用放在后台运行

driver.hideKeyboard(); //隐藏键盘

driver.lockDevice(); //锁屏

driver.openNotifications(); //打开Android的下拉通知栏

driver.isAppInstalled(“com.example.android.apis”) //判断应用是否安装

driver.installApp(“path/to/my.apk”) //安装应用

driver.removeApp(“com.example.android.apis”) //卸载应用

driver.closeApp() //关闭App

driver.getContextHandles() //可用上下文,context可以理解为可进入的窗口,如果是native则为native_app,如果是webview为对应webview;

driver.context(); //设置上下文 (context),对hybrid app会用到

driver.getAppStringMap(); //获取应用的字符串

driver.pressKeyCode(AndroidKeyCode.HOME); //给设备发送一个按键事件,所有键盘按键值可参考AndroidKeyCode类

driver.pullFile(“Library/AddressBook/AddressBook.sqlitedb”); //从设备中拉出文件

driver.pullFolder(“Library/AddressBook”); //从设备中拉出文件夹

driver.PushFile(“/data/local/tmp/file.txt”, “some data for the file”); //推送文件到设备中去

driver.swipe(75, 500, 75, 0, 0.8) //模拟用户滑动

driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(1)); //设置等待时间

driver.navigate().forward(); // 前进

driver.navigate().back(); // 后退

driver.navigate().refresh(); // 刷新

driver.currentActivity(); //当前activity,可用于断言跳转是否正确

driver.startActivity(appPackage,appActivity); //启动其他app的activity

坐标操作,降低适配带来的不适用:

double Screen_X = driver.Manage().Window.Size.Width;//获取手机屏幕宽度

double Screen_Y = driver.Manage().Window.Size.Height;//获取手机屏幕高度

double startX = element.Location.X; //获取元素的起点坐标,即元素最左上角点的横坐标

double startY = element.Location.Y; //获取元素的起点坐标,即元素最左上角点的纵坐标

double elementWidth = element.Size.Width; //获取元素的宽度

double elementHight = element.Size.Height; //获取元素的宽度

我对照着看了appium-client的官方文档,然后对着demo演示,发现一些个别API都找不到,查了下资料才发现,问题出现在:


public

static

AppiumDriver driver;

如果改成这样就ok了:


public

static

AndroidDriver driver;


这里要说下AppiumDriver和AndroiDriver的关系,AndroidDriver已经继承了AppiumDriver,在AppiumDriver基础上再封装一些基本功能。而AppiumDrvier是原生webdriver的子类,所以一些webdriver的方法都是适用的[Freeman1] 。


16、SDK android device monitor/android studio 进行android内存查看、Eclipse memory analyzer tool(MAT)分析内存获取详细信息。


安装MAT


下载安装:http://www.eclipse.org/mat/downloads.php


在线安装:http://archive.eclipse.org/mat/1.2/update-site/


Shallow Size

对象自身占用的内存大小,不包括它引用的对象。

针对非数组类型的对象,它的大小就是对象与它所有的成员变量大小的总和。当然这里面还会包括一些java语言特性的数据存储单元。

针对数组类型的对象,它的大小是数组元素对象的大小总和。


Retained Size

Retained Size=当前对象大小+当前对象可直接或间接引用到的对象的大小总和。(间接引用的含义:A->B->C, C就是间接引用)

换句话说,Retained Size就是当前对象被GC后,从Heap上总共能释放掉的内存。

不过,释放的时候还要排除被GC Roots直接或间接引用的对象。他们暂时不会被被当做Garbage



从上图可以看到它的大部分功能。

1. Histogram可以列出内存中的对象,对象的个数以及大小。

2. Dominator Tree可以列出那个线程,以及线程下面的那些对象占用的空间。

3.Top consumers通过图形列出最大的object。

4.Leak Suspects通过MA自动分析泄漏的原因。


Histogram如下图:


Objects:类的对象的数量。


Shallow size:就是对象本身占用内存的大小,不包含对其他对象的引用,也就是对象头加成员变量(不是成员变量的值)的总和。


Retained size:是该对象自己的shallow size,加上从该对象能直接或间接访问到对象的shallow size之和。换句话说,retained size是该对象被GC之后所能回收到内存的总和。


我们发现ThreadLocal和bingo.persister.dao.Daos类的对象占用了很多空间。

(十九)APP内存测试


常见的app内存测试工具:


Android Studio/Memory Monitor:观察Dalvik内存


Dumpsys meminfo:观察整体内存


Smaps:观察整体内存的详细组成


Eclipse Memory Analyzer:详细分析Dalvik内存


APP开发中关注内存:


尽量不要在循环中创建太多的临时变量


尽量把大型的循环拆散,分段或按需执行


引入SDK库和调用新的系统API时,主要不常用功能的消耗,可考虑多进程方案,影响内存放入临时进程执行


调整Dex文件的顺序可以优化空间

Native Heap:Native代码分配的内存,虚拟机和Android框架分配内存。关于什么是Native代码,即非Java代码分配的内存。详细介绍请找百度。


Dalvik Heap:Java对象分配的占据内存


Dalvik Other:类数据结构和索引占据内存


Stack:栈内存


Ashmem:不以dalvik- 开头的内存区域,匿名共享内存用来提供共享内存通过分配一个多个进程可以共享的带名称的内存块。匿名共享内存(Anonymous Shared Memory-Ashmem。Android匿名共享内存是基于Linux共享内存的,都是在tmpfs文件系统上新建文件,并将其映射到不同的进程空间,从而达到共享内存的目的,只是,Android在Linux的基础上进行了改造,并借助Binder+fd文件描述符实现了共享内存的传递。


Other dev:内部driver占用的内存


.so mmap C库代码占用的内存


.jar mmap java文件代码占用的内存


.apk mmap apk代码占用的内存


.ttf mmap ttf文件代码占用的内存


.dex mmap dex文件代码占用内存。类函数的代码和常量占用的内存,dex mmap是映射classex.dex文件,Dalvik虚拟机从dex文件加载类信息和字符串常量等。Dex文件有索引区和Data区


Other mmap 其它文件占用的内存


Pss:进程各部分内存的消耗,是所有进程pss相加得到系统占用内存的总和。


Dalvik heap Pss内存=私有内存Private Dirty+ 共享内存Share Dirty/共享的进程数Dalvik heap Pss内存=私有内存Private Dirty+ 共享内存Share Dirty/共享的进程数


Heap Size:Dalvik Heap总共的内存大小


Heap Alloc:所有应用实例分配的内存,包括了应用从zygote共享分享的内存


Native Heap Size 约等于Native Heap Alloc + Native Heap Free


主要内容就讲完了


(完)


点赞
收藏
回复
分享
举报
浏览2085 发布于2019-08-01 06:24未知归属地
全部评论
最多点赞
最新发布
最早发布
暂无评论
暂无评论
写回答
新增插入模板功能
一键使用模板,快速填写内容,轻松发帖~
知道了
  • 为了保障您的信息安全,请勿上传您的敏感个人信息(如您的密码等信息)和您的敏感资产信息(如关键源代码、签名私钥、调试安装包、业务日志等信息),且您需自行承担由此产生的信息泄露等安全风险。
  • 如您发布的内容为转载内容,请注明内容来源。

我要发帖子

了解社区公约,与您携手共创和谐专业的开发者社区。