移植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. 客户端调用代码举例
packagesample.demo.AppiumDemo;
importstaticorg.junit.Assert.*;
importjava.awt.image.BufferedImage;
importjava.io.File;
importjava.io.IOException;
importjava.net.URL;
importjavax.imageio.ImageIO;
importlibs.Util;
importio.appium.java_client.android.AndroidDriver;
importorg.apache.commons.io.FileUtils;
importorg.junit.After;
importorg.junit.Before;
importorg.junit.Test;
importorg.openqa.selenium.By;
importorg.openqa.selenium.OutputType;
importorg.openqa.selenium.WebElement;
importorg.openqa.selenium.remote.DesiredCapabilities;
publicclassCompareScreenShots{
privateAndroidDriverdriver;
@Before
publicvoidsetUp()throwsException{
DesiredCapabilitiescap=newDesiredCapabilities();
cap.setCapability("deviceName","Android");
cap.setCapability("appPackage","com.example.android.notepad");
cap.setCapability("appActivity",".NotesList");
driver=newAndroidDriver(newURL("http://127.0.0.1:4723/wd/hub"),cap);
}
@After
publicvoidtearDown()throwsException{
driver.quit();
}
@Test
publicvoidcompareScreenAndSubScreen()throwsInterruptedException,IOException{
Thread.sleep(2000);
WebElementel=driver.findElement(By.className("android.widget.ListView")).findElement(By.name("Note1"));
el.click();
Thread.sleep(1000);
Stringp1="C:/1";
Stringp2="C:/2";
Filef2=newFile(p2);
Filef1=driver.getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(f1,newFile(p1));
BufferedImageimg1=Util.getImageFromFile(f1);
f2=driver.getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(f2,newFile(p2));
BufferedImageimg2=Util.getImageFromFile(f2);
Booleansame=Util.sameAs(img1,img2,0.9);
assertTrue(same);
BufferedImagesubImg1=Util.getSubImage(img1,6,39,474,38);
BufferedImagesubImg2=Util.getSubImage(img1,6,39,474,38);
same=Util.sameAs(subImg1,subImg2,1);
Filef3=newFile("c:/sub-1.png");
ImageIO.write(subImg1,"PNG",f3);
Filef4=newFile("c:/sub-2.png");
ImageIO.write(subImg1,"PNG",f4);
}
}
  也不多解析了,没有什么特别的东西。
  大家用得上的就支持下就好了...

最新内容请见作者的GitHub页:http://qaseven.github.io/
相关文章
|
4月前
|
供应链 前端开发
如何做好供应商分级管理?一文讲清供应商全生命周期管理
本文探讨了供应商分级管理的必要性及合理分类方法,解析了如何通过供应商管理系统实现全生命周期管理,涵盖从潜在供应商评估到淘汰退出的各个环节。文章介绍了多种分级模式,如按合作关系、物料重要性及绩效评分进行分类,并结合DMAIC模型实现高效供应商管理。通过系统化策略,企业可提升管理效率、降低成本,优化供应链协同效率。
|
2月前
|
Cloud Native API 开发者
Gemini 2.5 Flash 技术拆解:从 MoE 架构到阿里云生态落地指南
2025年9月,谷歌Gemini 2.5 Flash发布,性能提升5%、成本降24%,引发行业关注。其MoE架构、百万上下文与“思考”范式,助力阿里云开发者高效构建云原生应用。本文解析技术内核,结合汽车、物流等案例,提供落地指南与避坑建议,展望大模型与流计算融合前景。
362 6
|
2月前
|
存储 人工智能 搜索推荐
Mem0 + Milvus:为人工智能构建持久化长时记忆
Mem0 为AI打造持久记忆层,结合Milvus向量数据库,让智能体记住用户偏好、追溯历史对话,实现个性化持续交互,告别“健忘”AI。
Mem0 + Milvus:为人工智能构建持久化长时记忆
|
10月前
|
Java
CentOS7.8配置Adoptium-Java17运行环境
本指南介绍如何设置清华镜像源并安装 Temurin-17-JRE 运行环境。首先,编辑 `/etc/yum.repos.d/adoptium.repo` 文件,配置清华镜像源。接着,使用 `yum install -y temurin-17-jre` 命令安装 Temurin-17-JRE,并通过 `java --version` 验证安装成功。相关配置和操作界面截图附后。
333 8
|
9月前
|
数据可视化 关系型数据库 MySQL
嵌入式C++、STM32、MySQL、GPS、InfluxDB和MQTT协议数据可视化
通过本文的介绍,我们详细讲解了如何结合嵌入式C++、STM32、MySQL、GPS、InfluxDB和MQTT协议,实现数据的采集、传输、存储和可视化。这种架构在物联网项目中非常常见,可以有效地处理和展示实时数据。希望本文能帮助您更好地理解和应用这些技术,构建高效、可靠的数据处理和可视化系统。
519 82
|
安全 IDE Java
Java串口通信技术探究2:RXTX库单例测试及应用
Java串口通信技术探究2:RXTX库单例测试及应用
471 4
|
存储 自然语言处理 算法
阿里云百炼之RAG算法能力分享会来喽|速来围观~
阿里云百炼是基于通义大模型、行业大模型以及三方大模型的一站式大模型开发平台。提供完整的模型训练工具和全链路开发套件,预置丰富的应用插件,提供便捷的集成方式,结合企业专属数据和API,帮企业高效完成大模型应用构建。RAG检索增强应用是在通义千问-Max大模型基础之上,专项增强「基于知识检索的大模型生成能力」,支持基于结构化/非结构化内容的文字生成场景。
970 5
|
Java Spring
spring boot 转 graalvm-native-images 的一些限制
spring boot 转 graalvm-native-images 的一些限制
|
移动开发 调度 C语言
移植一个实时OS很难?那就手把手教你如何快速移植一个RT-Thread Nano吧!
移植一个实时OS很难?那就手把手教你如何快速移植一个RT-Thread Nano吧!
590 0