简单介绍
项目一直是手工測试为主,加上一直是TV类应用。非常多自己主动化工具都没有针对TV类项目做非常好的适配,所以仅仅有自己动手了。
主要针对项目的特殊性进行了部分改造,不一定适用于其它项目。(涉及隐私,就不提供json文件和软件名字啦)
痛点
1.非标准控件的难处
通过uiautomatorviewer获取到的不一样的磁贴,属性所有同样(除了坐标点),意味着没法通过id和class+index方式获取。text属性为空,也就没有办法通过byText的方式获取uiobject,高度定制的磁贴,让自己主动化非常为难,假设通过坐标点。太坑爹,不能跨设备,还是坑。
2.TV类应用没有触摸操作
TV类安卓程序,主要面向的是遥控器。也就是接收的是keyevent。所以touch事件显得不这么全面,为了最接近用户。还是选择用key来做自己主动化。
架构模块
解析模块
从server解析json文件格式,包装成实体类CellInfo。返回一个包括磁铁信息的List。一个磁铁相应一个CellInfo。一个CellInfo须要提取的信息有
- x坐标
- y坐标
- 所属的Tab分类页
- 每一个磁铁的说明标签
所以相应的定义例如以下:
package launcherClick.model;
public class CellInfo {
private String label;
private String tab;
public String getTab() {
return tab;
}
public void setTab(String tab) {
this.tab = tab;
}
private int x;
private int y;
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
解析用的是第三方开源库org.json。相应的解析代码例如以下:
package launcherClick;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONObject;
import Utils.IOUtils;
import Utils.Println;
import launcherClick.model.CellInfo;
public class AMetroParse {
public static List<CellInfo> startParse(String url) {
String str = IOUtils.readFromNet(url);
if(str==null){
return null;
}
JSONObject jsonObject = new JSONObject(str);
List<CellInfo> list = new ArrayList<CellInfo>();
JSONArray _tabs = jsonObject.getJSONArray("tabs");
for(int i = 0;i<_tabs.length();i++){
String tab = _tabs.getJSONObject(i).getString("label");
JSONArray _cells = _tabs.getJSONObject(i).getJSONArray("cells");
for(int j=0;j<_cells.length();j++){
CellInfo cellInfo = new CellInfo();
cellInfo.setX(_cells.getJSONObject(j).getJSONObject("location").getInt("x"));
cellInfo.setY(_cells.getJSONObject(j).getJSONObject("location").getInt("y"));
cellInfo.setLabel(_cells.getJSONObject(j).getJSONObject("content").getString("label"));
cellInfo.setTab(tab);
list.add(cellInfo);
}
}
return list;
}
}
坐标转换模块
这部分的工作是把上一步骤解析后的实体类进行提取和处理,主要处理的内容是依据x y坐标计算磁铁移动量,更具x的极大值和分类页做跨分类移动的偏移计算以及一些其它处理。
通过x y计算偏移比較简单。仅仅是简单计算距离:
for (CellInfo cellInfo : list) {
if (cellInfo.getLabel().contains(label)
&& cellInfo.getTab().contains(tab)) {
int x = cellInfo.getX();
int y = cellInfo.getY();
new Println("x:" + x + " " + "y:" + y + " " + "偏移量" + _offset);
// x方向
for (int i = x + _offset; i > 1; i--) {
new Println("→" + " count is " + (x + _offset));
keyRight();
}
// y方向
for (int i = y; i > 1; i--) {
new Println("↓");
keyDown();
}
}
}
恩。里面有个偏移量,跨分类用的,偏移量是通过每一个分类下磁铁最大值得出来的。每一个分类最后一个磁铁的x值即为最大值。遍历当前分类下的所有磁铁的x,假设大于后面一个,则放在前面,下次再用这个值去比較以下的x值。
忘记这是什么排序算法了…囧…当然,也能够用Collections的自带的算法。
private int togicOffset(String tab) {
int lineLenth = 0;
List<CellInfo> list = AMetroParse
.startParse("我是隐藏的接口");
for (CellInfo cellInfo : list) {
if (cellInfo.getTab().contains(tab)) {
int x = cellInfo.getX();
lineLenth = lineLenth >= x ? lineLenth : x;
}
}
return lineLenth;
}
那么通过上面的排序之后,就能够得到每一个分类的偏移量,这样对于后面的分类磁贴,就能够知道磁贴在总体的真正位置啦,于是就能够開始移动了。
for (CellInfo cellInfo : list) {
if (cellInfo.getLabel().contains(label) && cellInfo.getTab().contains(tab)) {
int x = cellInfo.getX();
int y = cellInfo.getY();
new Println("x:" + x + " " + "y:" + y + " " + "偏移量" + _offset);
// x方向
for (int i = x + _offset; i > 1; i--) {
new Println("→" + " count is " + (x + _offset));
keyRight();
}
// y方向
for (int i = y; i > 1; i--) {
new Println("↓");
keyDown();
}
}
}
图片比較模块
来源于monkeyrunner的思路。原理是计算两个bitmap的长宽,然后提取出里面每一个像素的像素值。假设同样,类似度+1,最后再除以总像素值(比方1280x720),这样就能够把类似程度转为一个一个能够衡量的详细值了。那么推断这个界面是不是我须要点击的时候,仅仅须要截屏当前图片和预期的图片对照,类似度达到100的时候就觉得是正确的。当然也提供了局部比較的功能。比方获取不到数据的异常提示。那么代码例如以下。提供了多种重载的方法以及两个assert推断。
package Utils;
import junit.framework.Assert;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
public class ImageCompare {
public static void AssertBitmapEqual(Bitmap bitmap0, Bitmap bitmap1){
/**
* 百分百图片同样断言-.-
*/
Assert.assertEquals(100, ImageCompare(bitmap0,bitmap1));
}
public static void AssertBitmapNotEqual(Bitmap bitmap0, Bitmap bitmap1){
/**
* 百分之零图片同样断言
*/
Assert.assertEquals(0, ImageCompare(bitmap0,bitmap1));
}
public static int ImageCompare(String path0,String path1) {
/**
* 提供依据路径直接比較
*/
Bitmap bitmap0 = BitmapFactory.decodeFile(path0);
Bitmap bitmap1 = BitmapFactory.decodeFile(path1);
return ImageCompare(bitmap0,bitmap1);
}
public static int ImageCompareChild(Bitmap bitmap0, Bitmap bitmap1,int x,int y,int width,int height) {
/**
* 裁剪子图并比較,主要是为了解决拉取动态数据不同,可是局部提示不变的比較场景。
*/
Bitmap bitmap00 = bitmap0.createBitmap(bitmap0, x, y, width, height);
Bitmap bitmap01 = bitmap1.createBitmap(bitmap1, x, y, width, height);
return ImageCompare(bitmap00,bitmap01);
}
public static int ImageCompare(Bitmap bitmap0, Bitmap bitmap1) {
/**
* 比較的主函数
* 仅仅能比較同样长宽的图片。不相等返回-1失败
* 类似度为1~100
* 原理是提取每一个像素点比較,整张图类似度取决于像素点同样个数。所以还是比較准确的
*/
int picPct = 0;
int picCount = 0;
int picCountAll = 0;
new Println("begin to compare");
if (bitmap0 == null || bitmap1 == null) {
new Println("null bitmap");
return -1;
}
if (bitmap0.getWidth() != bitmap1.getWidth()
|| bitmap0.getHeight() != bitmap1.getHeight()) {
return -1;
}
new Println("宽度为:" + bitmap1.getWidth() + "高度为:" + bitmap1.getHeight());
for (int j = 0; j < bitmap1.getWidth(); j++) {
for (int i = 0; i < bitmap0.getHeight(); i++) {
if (bitmap0.getPixel(j, i) == bitmap1.getPixel(j, i)) {
picCount++;
}
picCountAll++;
}
}
int result = (int) (((float) picCount) / picCountAll * 100);
new Println(picCount + "/" + picCountAll);
new Println("类似度为:" + result);
return result;
}
}
异常&&其它模块
定义了一些异常类。主要功能用于提示。这个提示的作用后面会用到。
添加了启动应用和关闭应用的方法,原理是用到了shell命令。
Runtime.getRuntime().exec("am start -n 我是包名隐藏者");
初始化方法。主要用于异常时能够一键又一次開始。以及磁贴复原功能。还有其它一些小的处理就不多说啦。以下開始持续构建。
自己主动化的持续集成
还是那句话,不持续集成的自己主动化不是自己主动化,所以这里介绍的是基于jenkins的自己主动化集成,事实上UiAutomator做集成还是非常easy的。仅仅要把jar包放在一个固定的文件夹,然后shell命令运行就完事了。
然后定时任务自己选吧,构建失败的邮件提醒这里设置的是,上面我自己定义的异常类,当控制台输出我的异常类,那么会觉得不通过,然后触发邮件提醒。
那么至此。一个较为完整的流程就完毕啦,那么在此框架上组员们(就我一个)就能够更进一部去完好二级页面的自己主动化用例了。
举报
- 本文已收录于下面专栏:
相关文章推荐
-
android自己主动化測试-UiAutomator经常使用类
前面总结了uiautomator的用法: android自己主动化測试-UiAutomator使用入门 这里对我们写脚本时经常使用的一些类进行总结: UiDevice类: 1.takeScree...- whorus1
- 2016-04-01 15:24
- 710
-
android自己主动化測试框架(一) uiautomator
Android自己主动化測试主要分为Monkeyrunner、Rubotium、UiAutomator、Monkey等。主要特点:<br style="font-size: 14px; font-family: Arial; color: #333333; line-height: 2- 喜欢蓝色的我
- 2015-07-17 15:16
- 1476
-
谷歌原生自己主动化框架UiAutomator1.0
5小时搞定谷歌原生自己主动化框架UiAutomator1.0 原文 http://tmq.qq.com/2016/06/androidautotestframwork-uiautomator/ ...- chen110juan
- 2016-07-01 11:32
- 242
-
android自己主动化測试框架(一) uiautomator(2)
waitForWindowUpdate(final String packageName, long timeout) 等待符合packageName的应用触发 <- 喜欢蓝色的我
- 2015-07-17 17:27
- 304
-
【腾讯TMQ】5小时搞定谷歌原生自己主动化框架UiAutomator1.0
谷歌对UI測试(UI Tetsting)的概念是:确保用户在一系列操作过程中(比如键盘输入、点击菜单、弹出对话框、图像显示以及其它UI控件的改变)。你的应用程序做出正确的UI响应。- TMQ1225
- 2016-06-23 14:40
- 4306
-
基于android的web app 自己主动化測试
乔布斯有一次谈到这个问题,他说Web是未来。尽管现阶段Native给了用户更好的体验。假设现
- EdwPhoebus
- 2013-03-30 01:08
- 825
-
UiAutomator自己主动化測试框架的使用
简单介绍UiAutomator 是 Google 在 Android4.1 推出的一套黑盒 UI 自己主动化測试框架。用于做 UI 自己主动化的框架,主要模拟人来操作手机,如点击、长按、滑动、按键、文本输入等操作...- codeteenager
- 2017-07-28 17:18
- 52
-
Android UiAutomator 自己主动化測试
一、一个BUG引发的问题 假设研发过程中有一个BUG:“不断的切换手机语言出现花屏现象”。这个问题我们怎样验证呢?我想,最好的方式应该是自己主动化測试。 那么,自己主动化測试能够完毕哪些任务呢? 简单的说,那些反复性的測试工作,都能够交给自己主动化完毕: 1、设置手机的语言 2、加入、删除、收藏联系人 3、拨号、挂断 4、甚至发送短信、收藏短信 假设须要上面的功能。那么就開始自己主动化之旅吧。二、Android自己主动化測试简介 Android自己主动化測试主要分为Mo
- quanminchaoren
- 2014-07-04 17:39
- 2168
-
5小时搞定谷歌原生自己主动化框架UiAutomator1.0
转载地址:http://tmq.qq.com/2016/06/androidautotestframwork-uiautomator/ 谷歌对UI測试(UI Tetsting)的概念是:...- wanglha
- 2016-07-04 09:31
- 822
0条评论