在Selenium Grid的不同PC上拥有不同尺寸的屏幕截图

问题描述:

我正在使用Selenium Grid在不同PC上执行GWT Web应用程序的跨浏览器测试。我面临的问题是生成的屏幕截图的大小(在测试过程中获得的)对于不同的PC是不同的,我想让我的代码具有通用性,即设置屏幕截图的默认大小。这里是我用来截取屏幕截图的代码,然后将生成的图像与本地PC上存储的图像进行比较。在Selenium Grid的不同PC上拥有不同尺寸的屏幕截图

首先我会调用CallScreenshotAndCompareImage方法和 参数(canvas,className)。

这里的画布是代表GWT应用程序中的HTML5画布的WebElement 。

FileBase是本地存储在我的项目中的文件,fileActual是生成的截图。

public class Browser { 
    //ThreadLocal will provide thread-safe tests 
     protected ThreadLocal<RemoteWebDriver> threadLocal = null; 
     String serverMachine = "xxx.xxx.xxx.xxx:xxx/hub"; //IP Address of hub 
     @BeforeTest 
     @Parameters("browser") 
     public void setup(String browser) throws MalformedURLException{ 

      if(browser.equalsIgnoreCase("chrome")) { 

       System.setProperty("webdriver.chrome.driver", ".src/Drivers/chromedriver.exe"); 
       DesiredCapabilities capability = null; 
       capability = DesiredCapabilities.chrome(); 
       capability.setPlatform(Platform.WINDOWS); 
       capability.setBrowserName("chrome"); 
       createRemoteWebDriver(capability); 
      } 
      else if(browser.equalsIgnoreCase("firefox")) { 

       System.setProperty("webdriver.gecko.driver", ".src/Drivers/geckodriver.exe"); 
       DesiredCapabilities capability = null; 
       capability = DesiredCapabilities.firefox(); 
       capability.setPlatform(Platform.WINDOWS); 
       capability.setBrowserName("firefox"); 
       createRemoteWebDriver(capability); 
      } 

     } 
     public void createRemoteWebDriver(DesiredCapabilities capability) throws MalformedURLException { 
      threadLocal = new ThreadLocal<RemoteWebDriver>(); 
      threadLocal.set(new RemoteWebDriver(new URL(serverMachine), capability)); 
     } 

     public WebDriver getDriver() { 
      return threadLocal.get(); 
     } 

public void CallScreenshotAndCompareImage(WebElement element, String className) throws IOException, InterruptedException { 
      File fileBase1 = new File("./src/Images/baseDrawing"+className+"Chrome.png"); 
      File fileBase2 = new File("./src/Images/baseDrawing"+className+"Firefox.png"); 
      Capabilities cap = ((RemoteWebDriver) getDriver()).getCapabilities(); 
      String browserName = cap.getBrowserName().toLowerCase(); 
      File fileActual = new File("./src/Images/actualDrawing"+className+browserName+".png"); 
      File elementImage = this.takeElementScreenshot(element,"png"); 
      FileUtils.copyFile(elementImage, fileActual); 
      if(browserName.equalsIgnoreCase("chrome")) 
       this.compareImage(fileBase1,fileActual); 
      else if(browserName.equalsIgnoreCase("firefox")) 
       this.compareImage(fileBase2,fileActual); 
      Thread.sleep(3000); 
     } 

public File takeElementScreenshot(WebElement element, String imageFormat) throws IOException{ 

      Point elementXY = element.getLocation(); 
      int elementHeight = element.getSize().getHeight(); 
      int elementWidth = element.getSize().getWidth(); 
      Rectangle elementRectArea = new Rectangle(elementWidth,elementHeight); 
      WrapsDriver wrapsDriver = (WrapsDriver) element; 
      File pageImage = ((TakesScreenshot)wrapsDriver.getWrappedDriver()).getScreenshotAs(OutputType.FILE); 
      BufferedImage bufferedImage = ImageIO.read(pageImage); 
      BufferedImage elementImage = bufferedImage.getSubimage(elementXY.getX(), elementXY.getY(), elementRectArea.width, elementRectArea.height); 
      ImageIO.write(elementImage, imageFormat, pageImage); 
      return pageImage; 
     } 

     public void compareImage(File fileBase, File fileActual) { 
      /* 
     STEPS: 
     1) For first image file, recognize the contents of the file and decodes it into a BufferedImage which can be directly used by Java 2D. 
     2) Get the raster from the bufferedImage object which is a copy of image data. 
     3) Get the DataBuffer associated with the raster. 
     4) Get the size of the all the banks(data arrays) for the DataBuffer object. 
     5) Repeat steps 1-4 for the second image file. 
     6) If sizes of both of the images are different, then images won't be same. 
     7) If sizes are same, then compare all the data array elements for both of the DataBuffer objects. If they are same. then both images will be same. 
      */ 

      try { 

       BufferedImage bufferedImage = ImageIO.read(fileBase); 
       DataBuffer dataBufferFirst = bufferedImage.getData().getDataBuffer(); 
       int sizeFirst = dataBufferFirst.getSize();    
       BufferedImage bufferedImage2 = ImageIO.read(fileActual); 
       DataBuffer dataBufferSecond = bufferedImage2.getData().getDataBuffer(); 
       int sizeSecond = dataBufferSecond.getSize(); 
       int count=0; 
       Assert.assertEquals(sizeFirst, sizeSecond,"Size of Base Drawing and actual Drawing is not same"); 
       if(sizeFirst == sizeSecond) 
       { 
        for(int i=0; i<sizeFirst; i++) 
        { 
         if(dataBufferFirst.getElem(i) != dataBufferSecond.getElem(i)) //getElem() returns the data array element at the specified index. 
         { 
          count++; 
         } 

        } 
        Assert.assertEquals(count, 0,"Both images are not same"); 
       } 
      } catch (Exception e) { 
       Assert.fail("Failed to compare image files...!!!"); 
      } 
     } 
} 

运行此代码,当我比较两个基座(本地)图像和实际的(生成的)图像的属性后,再有就是这两个图像之间的差别不大。

基本绘图:尺寸 - > 253 KB,位深度 - > 32,尺寸 - > 1570 X 873个像素

实际绘制:尺寸 - > 232 KB,位深度 - > 24 ,尺寸 - > 1570 x 873像素

其他所有内容在这两个图像的属性中都是相同的。

我应该在我的代码中添加什么,以便来自不同PC的生成的屏幕截图始终具有相同的大小?

虽然@Florent B.的回答给了我一个方向,以找出解决方案,但在这里我就是这样做来解决这个问题。

  1. 检查图像的位深度是24还是32。
  2. 如果它是32,然后从它删除所有的alpha通道。
  3. 接下来,我设置了一个范围,如果两个相应图像的像素的RGB值之间的差值小于10,则将这些图像视为相同。

我想你必须使用一个命令来设置执行的驱动程序的分辨率。 这样做加入Java

driver.manage().window().setSize(new Dimension (1280, 1024)); 

在你的测试步骤之前。 现在截图将始终具有相同的分辨率。

+0

但是我的图像的分辨率是一样的,这不是我的问题。主要问题与图像大小(和位深度)有关,而不是分辨率。请仔细阅读我在问题详细信息结尾处的块引用中指定的内容。 – DG4

+0

好的这个信息本来是有用的。 –

问题不是图像的大小,而是Alpha通道(透明度),它存在于基础绘图中,并且在屏幕截图中缺失。

该驱动程序应该返回一个PNG Base64编码的字符串。但没有说明它应该是24位RGB还是32位RGBA PNG。 因此,为了能够比较缓冲区,您首先必须将它们中的每一个转换为所需的颜色空间。

下面是一个例子:

public static void main(String[] args) throws Exception { 
    BufferedImage imageA = ImageIO.read(new File("C:\\temp\\img_24bits.png")); 
    BufferedImage imageB = ImageIO.read(new File("C:\\temp\\img_32bits.png")); 
    boolean same = isSameImage(imageA, imageB); 
} 

public static boolean isSameImage(BufferedImage imageA, BufferedImage imageB) throws IOException { 
    DataBufferInt bufferA = getImageBuffer(imageA); 
    DataBufferInt bufferB = getImageBuffer(imageB); 

    if (bufferA.getSize() != bufferB.getSize() || bufferA.getNumBanks() != bufferB.getNumBanks()) 
     return false; 

    for (int i = 0; i < bufferA.getNumBanks(); ++i) { 
     if (!Arrays.equals(bufferA.getData(i), bufferB.getData(i))) 
      return false; 
    } 

    return true; 
} 

private static DataBufferInt getImageBuffer(BufferedImage img) throws IOException { 
    BufferedImage bi = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB); 
    ColorConvertOp cco = new ColorConvertOp(bi.getColorModel().getColorSpace(), img.getColorModel().getColorSpace(), null); 
    cco.filter(img, bi); 
    return (DataBufferInt)bi.getRaster().getDataBuffer(); 
} 
+0

我试过你的方法,但仍然说这两个图像是不同的。我通过打印相同变量的布尔值来检查。 – DG4

+0

如果该方法返回false,则图像与至少一个具有不同颜色的像素不同。这可能是肉眼看不到的,但不同之处在于。这可能是由于不同的抗锯齿。严格的像素比较只能用于比较来自同一浏览器的屏幕截图。要比较浏览器之间的屏幕截图,您必须应用一些过滤器来缩小要验证的功能。看看图像魔术。 –

+0

你在说什么样的过滤器?就像允许图像中的至少一个或两个不同的像素或其他一些滤镜一样? – DG4