APP自動化測試之UiAutomator2.0顏色驗證方案

移動端APP的Android自動化測試中會有不少背景色、透明度等測試驗證,但各種測試框架都沒有提供獲取對象背景色等API,那么面對這樣的測試需求,我們該如何進行呢?
一、方案思路
直接在測試框架上面做文章貌似不可行了,那么我們就要轉向Android系統(tǒng)本身了,要驗證背景色,首先自然得獲取顏色值,UIAutomator2.0等框架沒有提供對應API,那么我們還可以通過截圖的方式獲取元素圖片,最直接的方式就可以通過像素點的方式獲取顏色值,這樣獲得的顏色值是基于RGB數(shù)值的……這好像有點抽象,還是先了解這些顏色空間概念:
1、RGB顏色模型
在圖像處理中,最常用的顏色空間是RGB模型,常用于顏色顯示和圖像處理,它是三維坐標的模型形式,如下圖表示一個三維坐標空間:

其他太復雜的原理我在這里就不深究(畢竟不是做圖像開發(fā),再深入的我也不懂了),我們只需要了解RGB模型的3維坐標系(r,g,b)分別代表的是紅綠藍三基色的值:
red紅色值(0~255)
green綠色值(0~255)
blue藍色值(0~255)
2、HSV顏色模型
HSV模型是一個倒錐形模型,如下圖所示:

這個模型是按色彩、深淺、明暗(透明度)來描述的,其中:
H:表示色彩,即色度值
S:表示深淺, 即通常說的透明度指標,S = 0時,只有灰度
V:表示明暗,說明色彩的明亮程度
3、RGB與HSV之間的關系
這段其實我不想貼,但是有些學霸還是看得明白的,那就當個搬運工,給學霸們看吧,不想了解原理的童鞋直接跳過關系這塊。直觀的理解,把RGB三維坐標的中軸線立起來,并扁化,就能形成HSV的錐形模型了。但V與強度無直接關系,因為它只選取了RGB的一個最大分量。而RGB則能反映光照強度(或灰度)的變化。
由RGB到HSV的轉換:

OK,言歸正傳,了解了上面這些顏色模型之后,可以清楚的發(fā)現(xiàn)使用HSV可以較大程度的排除掉光線或者分辨率等深淺明暗等外在因素導致的色差,直接去顏色值H可以較準確的進行顏色對比。然而我們通過取截圖的像素點顏色得到的RGB三維數(shù)組,那么要想實現(xiàn)HSV模型的H值對比,還得進行轉換,轉換的計算規(guī)則就是上面3中的RGB與HSV轉換計算(網上大多是C++版本的轉換,我下面給出Java版本的實現(xiàn))。
二、實現(xiàn)代碼
下面列舉出核心代碼并說明:
RGB數(shù)組轉換為HSV數(shù)組,一般只用HSV數(shù)組的色度值H和飽和度S
public?static?double[]?rgbToHsv(int?r,?int?g,?int?b){
????double?h,?s,?v;
????double?min,?max,?delta;
????min?=?Math.min(Math.min(r,?g),?b);
????max?=?Math.max(Math.max(r,?g),?b);
????//?V?亮度
????v?=?max;
????delta?=?max?-?min;
????//?S?飽和度
????if(?max?!=?0?)?{
????????s?=?delta?/?max;
????}else?{
????????s?=?0;
??????h?=?-1;
??????return?new?double[]{h,s,v};
????}
??????//?H?色度
????if(?r?==?max?){
????????h?=?(g?-?b)?/?delta;?//?between?yellow?&?magenta
????}else?if(?g?==?max?)?{
????????h?=?2?+?(b?-?r)?/?delta;?//?between?cyan?&?yellow
????}else?{
????????h?=?4?+?(r?-?g)?/?delta;?//?between?magenta?&?cyan
????}
??????h?*=?60;????//?degrees
????if(?h?0?)?{
????????h?+=?360;
????}
????return?new?double[]{h,s,v};
}獲取對象區(qū)域的指定像素點RGB模型數(shù)組值
/**
?*?圖片區(qū)域中指定坐標的rgb
?*?@param?rect
?*?@param?filePath
?*?@param?pixelX
?*?@param?pixelY
?*?@return
?*/
public?static?int[]?getColorRgb(Rect?rect,?String?filePath,?
??????int?pixelX,?int?pixelY)?{
????BitmapFactory.Options?bfOptions?=?new?BitmapFactory.Options();
????bfOptions.inDither?=?false;
????bfOptions.inTempStorage?=?new?byte[12?*?1024];
????bfOptions.inJustDecodeBounds?=?true;
????Bitmap?m?=?BitmapFactory.decodeFile(filePath);
????m?=?m.createBitmap(m,?rect.left,?rect.top,?
????????rect.width(),?rect.height());//獲取區(qū)域
????int?color?=?m.getPixel(pixelX,?pixelY);
????int?r?=?Color.red(color);
????int?g?=?Color.green(color);
????int?b?=?Color.blue(color);
????m.recycle();
????int?[]?rgb?=?{r,g,b};
????return?rgb;
}
驗證顏色方法,顏色對比驗證方法的驗證邏輯是首先比對RGB,RGB不一致再對比HSV的色度值H:
public?static?boolean?assertColor(int[]?actualRgb,?int[]?expectedRgb,?String?msg){
?????if(actualRgb?==?null?||?expectedRgb?==?null?||?actualRgb.length?!=?3?
????????||?expectedRgb.length?!=?3){
????????BaseCase.log.e("RGB數(shù)組為空或長度不為3",?isPrintLog);
????????return?false;
?????}
?????String?actual?=?TestUtil.rgbToString(actualRgb);
?????String?expected?=?TestUtil.rgbToString(expectedRgb);
????try?{
????????org.junit.Assert.assertEquals(actual,?expected);
????????BaseCase.log.i("實際"+?msg?+"的RGB值:\""+actual+"\"?,
?????????????????跟期望"+?msg?+"的RGB值:\""+expected+"\"?相匹配",?isPrintLog);
????????return?true;
????}?catch?(Error?e)?{
????????BaseCase.log.i("實際"+?msg?+"的RGB值:\""+actual+"\"?,
?????????????跟期望"+?msg?+"的RGB值:\""+expected+"\"?不匹配,下面對比HSV的色度值:");
????????double[]?actualHsv?=?TestUtil.rgbToHsv(actualRgb[0],actualRgb[1],actualRgb[2]);
????????double[]?expectedHsv?=?TestUtil.rgbToHsv(expectedRgb[0],expectedRgb[1],expectedRgb[2]);
????????double?hRate?=?Math.abs(actualHsv[0]-expectedHsv[0])/actualHsv[0];
????????double?sRate?=?Math.abs(actualHsv[1]-expectedHsv[1])/actualHsv[1];
????????if(hRate?0.05){
????????????????BaseCase.log.i("實際"+?msg?+"的HSV色度值:\""+actualHsv[0]+"\"?,
?????????????跟期望"+?msg?+"的色度值:\""+expectedHsv[0]+"\"?相匹配",?isPrintLog);
???????????return?true;
????????}
????????if(isPrintLog){
????????????BaseCase.log.e("實際"+?msg?+"的HSV色度值:\""+actualHsv[0]+"\"?,
?????????????跟期望"+?msg?+"的色度值:\""+expectedHsv[0]+"\"?不匹配",?isPrintLog);
??????}
????????return?false;
????}
}
驗證透明度方法,透明度驗證使用HSV模型的S值來對比:
public?static?boolean?assertAlpha(int[]?actualRgb,?double?expectedAlpha,?String?msg){
?????if(actualRgb?==?null?||?actualRgb.length?!=?3){
??????????BaseCase.log.e("RGB數(shù)組為空或長度不為3",isPrint);
???????return?false;
????}
??????double?hsv_s?=?rgbToHsv(actualRgb[0],actualRgb[1],actualRgb[2])[1];
????hsv_s?=?(double)Math.round(hsv_s*1000)/1000.0;
????double?actualAlpha?=?Double.parseDouble(new?DecimalFormat("0.0").format(hsv_s));
????try?{
????????????org.junit.Assert.assertEquals(actualAlpha,?expectedAlpha);
????????BaseCase.log.i("實際"+?msg?+"的透明度:\""+actualAlpha+"\"?,跟期望"+?msg?+"的透明度:\""+expectedAlpha+"\"?相匹配",isPrint);
????????return?true;
????}?catch?(Error?e)?{
????????????double?sRate?=?hsv_s?>?0.0???Math.abs(hsv_s-expectedAlpha)/hsv_s?:?1;
????????if(hsv_s?==?expectedAlpha){
????????????????BaseCase.log.i("實際"+?msg?+"的透明度:\""+actualAlpha+"\"?,
?????????????跟期望"+?msg?+"的透明度:\""+expectedAlpha+"\"?相匹配",isPrint);
????????????return?true;
????????}?else?if(sRate?0.1){
????????????????BaseCase.log.i("實際"+?msg?+"的透明度:\""+actualAlpha+"\"?,
?????????????跟期望"+?msg?+"的透明度:\""+expectedAlpha+"\"?在誤差范圍內相匹配",isPrint);
???????????return?true;
????????}
????????if(isPrint){
????????????BaseCase.log.e("實際"+?msg?+"的透明度:\""+actualAlpha+"\"?,
?????????????跟期望"+?msg?+"的透明度:\""+expectedAlpha+"\"?不匹配",isPrint,?msg?+?"不匹配");
???????}
????????return?false;
???}
}
測試用例方法中驗證顏色示例:
int[]?bgColorRgb?=?TestUtil.getRandomColorRgb();
setText(getImageBgColor(),TestUtil.rgbToString(bgColorRgb));assertColor(getColor(adPage.getAdImage(),0,0),bgColorRgb,"大圖背景色");
三、總結
用這種方式驗證顏色感覺妥妥的,但是也有可能會出現(xiàn)不準的情況,因為是基于像素點取色,依賴于像素點的坐標,然而對于不是純色的顏色或者圖片包含其他雜色,這時候使用像素點就不能隨便取了,你可以拿一個準確的點,或者可以不用考慮效率的話,采用遍歷全區(qū)域取色,再計算占比,將占比最大的RGB值返回,這樣準確率肯定高了,但是效率就慢了,特別是對比尺寸較大的圖,圖像對比操作本來就效率較低且很耗系統(tǒng)資源,所以一般做圖像處理的都用C++,當然市面上好像也有一些比較好的圖像對比算法和框架,想進一步研究就得靠自己去看文檔和研究了。
測試開發(fā)棧
軟件測試開發(fā)合并必將是趨勢,不懂開發(fā)的測試、不懂測試的開發(fā)都將可能被逐漸替代,因此前瞻的技術儲備和知識積累是我們以后在職場和行業(yè)脫穎而出的法寶,期望我們的經驗和技術分享能讓你每天都成長和進步,早日成為測試開發(fā)棧上的技術大牛~~
長按二維碼/微信掃描關注
互聯(lián)網測試開發(fā)一站式全棧分享平臺
