1. 程式人生 > >移植MonkeyRunner的圖片對比和獲取子圖功能的實現-Appium篇

移植MonkeyRunner的圖片對比和獲取子圖功能的實現-Appium篇

如果你的目標測試app有很多imageview組成的話,這個時候monkeyrunner的截圖比較功能就體現出來了。而其他幾個流行的框架如Robotium,UIAutomator以及Appium都提供了截圖,但少了兩個功能:
  • 獲取子圖
  • 圖片比較
既然Google開發的MonkeyRunner能盛行這麼久,且它體功能的結果驗證功能只有截圖比較,那麼必然有它的道理,有它存在的價值,所以我們很有必要在需要的情況下把它相應的功能給移植到其他框架上面上來。 經過本人前面文章描述的幾個框架的原始碼的研究(robotium還沒有做),大家可以知道MonkeyRunner是跑在PC端的,只有在需要傳送相應的命令事件時才會驅動目標機器的monkey或者shell等。比如獲取圖片是從目標機器的buffer裝置得到,但是比較圖片和獲取子圖是從客戶PC端做的。 這裡Appium工作的方式非常的類似,因為它也是在客戶端跑,但需要注入事件傳送命令時還是通過目標機器段的bootstrap來驅動uiatuomator來完成的,所以要把MonkeyRunner的獲取子圖已經圖片比較的功能移植過來是非常容易的事情。 但UiAutomator就是另外一回事了,因為它完全是在目標機器那邊跑的,所以你的程式碼必須要android那邊支援,所以本人在移植到UiAutomator上面就碰到了問題,這裡先給出Appium 上面的移植,以方便大家的使用,至於UiAutomator和Robotium的,今後本人會酌情考慮是否提供給大家。 還有就是這個移植過來的程式碼沒有經過優化的,比如失敗是否儲存圖片以待今後檢視等。大家可以基於這個基礎實現滿足自己要求的功能

1. 移植程式碼

移植程式碼放在一個Util.java了工具類中:
	public static boolean sameAs(BufferedImage myImage,BufferedImage otherImage, double percent)
	{
		//BufferedImage otherImage = other.getBufferedImage();
	     //BufferedImage myImage = getBufferedImage();
	     
	
	     if (otherImage.getWidth() != myImage.getWidth()) {
	       return false;
	     }
	     if (otherImage.getHeight() != myImage.getHeight()) {
	       return false;
	     }
	     
	     int[] otherPixel = new int[1];
	     int[] myPixel = new int[1];
	     
	     int width = myImage.getWidth();
	     int height = myImage.getHeight();
	     
	     int numDiffPixels = 0;
	     
	     for (int y = 0; y < height; y++) {
	       for (int x = 0; x < width; x++) {
	         if (myImage.getRGB(x, y) != otherImage.getRGB(x, y)) {
	           numDiffPixels++;
	         }
	       }
	     }
	     double numberPixels = height * width;
	     double diffPercent = numDiffPixels / numberPixels;
	     return percent <= 1.0D - diffPercent;
	   }
	
	   public static BufferedImage getSubImage(BufferedImage image,int x, int y, int w, int h)
	   {
	     return image.getSubimage(x, y, w, h);
	   }
	   

		public static BufferedImage getImageFromFile(File f) {
		
			BufferedImage img = null;
			
			try {
				img = ImageIO.read(f);
				
			} catch (IOException e) {
				//if failed, then copy it to local path for later check:TBD
				//FileUtils.copyFile(f, new File(p1));
				e.printStackTrace();
				System.exit(1);
			}
			return img;
		}
這裡就不多描述了,基本上就是基於MonkeyRunner做輕微的修改,所以叫做移植。而UiAutomator就可能需要大改動,要重現實現了。

2. 客戶端呼叫程式碼舉例

package sample.demo.AppiumDemo;

import static org.junit.Assert.*;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;

import libs.Util;
import io.appium.java_client.android.AndroidDriver;

import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;

public class CompareScreenShots {

	private AndroidDriver driver;
	
	@Before
	public void setUp() throws Exception {
		DesiredCapabilities cap = new DesiredCapabilities();
		cap.setCapability("deviceName", "Android");
		cap.setCapability("appPackage", "com.example.android.notepad");
		cap.setCapability("appActivity", ".NotesList");
		
		driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"),cap);
	}

	@After
	public void tearDown() throws Exception {
		driver.quit();
	}

	@Test
	public void compareScreenAndSubScreen() throws InterruptedException, IOException{
		Thread.sleep(2000);
		
		WebElement el = driver.findElement(By.className("android.widget.ListView")).findElement(By.name("Note1"));
		el.click();
		Thread.sleep(1000);
		String p1 = "C:/1";
		String p2 = "C:/2";

		File f2 = new File(p2);
		
		File f1 = driver.getScreenshotAs(OutputType.FILE);
		FileUtils.copyFile(f1, new File(p1));
		
		BufferedImage img1 = Util.getImageFromFile(f1);
		
		f2 = driver.getScreenshotAs(OutputType.FILE);
		FileUtils.copyFile(f2, new File(p2));
		BufferedImage img2 = Util.getImageFromFile(f2);

		
		Boolean same = Util.sameAs(img1, img2, 0.9);
		assertTrue(same);
		
		BufferedImage subImg1 = Util.getSubImage(img1, 6, 39, 474, 38);
		BufferedImage subImg2 = Util.getSubImage(img1, 6, 39, 474, 38);
		same = Util.sameAs(subImg1, subImg2, 1);
		
		File f3 = new File("c:/sub-1.png");
		ImageIO.write(subImg1, "PNG", f3);
		
		File f4 = new File("c:/sub-2.png");
		ImageIO.write(subImg1, "PNG", f4);
		
	}

	
}
也不多解析了,沒有什麼特別的東西。 大家用得上的就支援下就好了...