編輯:關於Android編程
項目一直是手工測試為主,加上一直是TV類應用,很多自動化工具都沒有針對TV類項目做很好的適配,所以只有自己動手了。主要針對項目的特殊性進行了部分改造,不一定適用於其他項目。(涉及隱私,就不提供json文件和軟件名字啦)
1.非標准控件的難處
通過uiautomatZ喎?/kf/ware/vc/" target="_blank" class="keylink">vcnZpZXdlcrvxyKG1vbXEsrvSu9H5tcS0xcz5o6zK9NDUyKuyv8/gzawos/3By9f4seq14ymjrNLizrbXxcO7t6jNqLn9aWS6zWNsYXNzK2luZGV4t73KvbvxyKGjrHRleHTK9NDUzqq/1aOs0rK+zcO709Cw7Leozai5/WJ5VGV4dLXEt73KvbvxyKF1aW9iamVjdKOsuN+2yLao1sa1xLTFzPmjrMjD19S2r7uvutzOqsTRo6zI57n7zai5/df4seq146OszKu/07X5o6yyu8Tcv+fJ6LG4o6y7ucrHv9OhozwvcD4NCjxwPjxzdHJvbmc+Mi5UVsDg06bTw8O709C0pcP+stnX9zwvc3Ryb25nPjxiciAvPg0KVFbA4LCy17+zzNDyo6zW99Kqw+bP8rXEysfSo7/YxvejrNKyvs3Kx73TytW1xMrHa2V5ZXZlbnSjrMv50tR0b3VjaMrCvP7P1LXDsrvV4sO0yKvD5qOszqrBy9fuvdO9/NPDu6ejrLu5ysfRodTx08NrZXnAtNf219S2r7uvoaM8L3A+DQo8aDIgaWQ9"架構模塊">架構模塊
從服務器解析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 startParse(String url) {
String str = IOUtils.readFromNet(url);
if(str==null){
return null;
}
JSONObject jsonObject = new JSONObject(str);
List list = new ArrayList();
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 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做集成還是很容易的,只要把jar包放在一個固定的目錄,然後shell命令執行就完事了。
然後定時任務自己選吧,構建失敗的郵件提醒這裡設置的是,上面我自定義的異常類,當控制台輸出我的異常類,那麼會認為不通過,然後觸發郵件提醒。
那麼至此,一個較為完整的流程就完成啦,那麼在此框架上組員們(就我一個)就可以更進一部去完善二級頁面的自動化用例了。
銀聯支付也是一般比較常用的支付功能,這裡簡單了介紹android app如果短期快速應用這一方面的東西。直接上代碼: 1.導入銀聯支付的依賴包: 2.在res目錄下增
自己寫db文件方法有兩種:1、用sql server2005+sqlserver2sqlite_converter工具(數據在sql server裡面寫)2、用Excel
自學安卓,無論開發環境是Eclipse還是Android Studio,都少不了和Android SDk打交道,作為一名安卓小白,在當初剛開始安裝配置Android開發環
關於使用MarkDown編輯器的原因 其實前段時間就支持使用MarkDown編輯器來寫博客了,只是由於當時接觸過MarkDown,所以之前的博客都是使用默認的HTML編輯