跟测试老兵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;
 

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

16SDK 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-AshmemAndroid匿名共享内存是基于Linux共享内存的,都是在tmpfs文件系统上新建文件,并将其映射到不同的进程空间,从而达到共享内存的目的,只是,AndroidLinux的基础上进行了改造,并借助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 SizeDalvik Heap总共的内存大小

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

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

主要内容就讲完了,你学得怎么样?欢迎跟我交流。36115774

(完)

 

 

 

 

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

manok

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值