【问题标题】:Screenshots having different sizes on different PCs in Selenium GridSelenium Grid 中不同 PC 上不同大小的屏幕截图
【发布时间】:2018-03-22 18:36:31
【问题描述】:

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

首先我将调用 CallScreenshotAndCompareImage 方法 参数(画布、类名)。

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

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 生成的屏幕截图始终具有相同的大小?

【问题讨论】:

    标签: java selenium gwt screenshot selenium-grid


    【解决方案1】:

    虽然@Florent B. 的回答为我提供了解决方案的方向,但这是我为解决此问题所做的工作。

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

    【讨论】:

      【解决方案2】:

      问题不在于图像的大小,而在于基本绘图中存在但在屏幕截图中缺失的 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();
      }
      

      【讨论】:

      • 我试过你的方法,但还是说两张图片都不一样。我通过打印同一变量的布尔值来检查这一点。
      • 如果该方法返回false,则图像不同,至少有一个像素具有不同的颜色。它可能是肉眼看不见的,但区别就在那里。这可能是由于不同的抗锯齿。严格像素比较只能用于比较来自同一浏览器的屏幕截图。要比较浏览器之间的屏幕截图,您必须应用一些过滤器来缩小您尝试验证的功能。看看图像魔术。
      • 您说的是哪种过滤器?比如允许图像中至少有一个或两个不同的像素或其他一些过滤器?
      • 这取决于差异是什么以及您要验证的内容。它可以是边缘、锐化、高斯......您还可以使用特定算法来忽略抗锯齿:github.com/mapbox/pixelmatch
      【解决方案3】:

      我认为您必须使用命令来设置执行驱动程序的分辨率。 为此,请在 Java 中添加

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

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

      【讨论】:

      • 但是我的图片分辨率是一样的,这不是我的问题。主要问题与不同的图像大小(和位深度)有关,而不是分辨率。请阅读我在问题详细信息末尾的块引用中指定的内容。
      猜你喜欢
      • 2015-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-13
      • 1970-01-01
      • 1970-01-01
      • 2016-09-10
      • 2016-05-05
      相关资源
      最近更新 更多