Many a time, our tests need image-based comparison. For example, verifying whether correct icons are displayed, verifying whether correct images are displayed in web pages, or comparing the baseline screen layout with the actual layout.
Selenium WebDriver does have features to capture screenshots or images from the application under test; however, it does not have the feature to compare the images.
In this recipe, we will create an extension class to compare images and use it in our Selenium tests.
Set up a new Java project for the CompareUtil
class. This class will be used by Selenium tests as an extension to compare images.
Let's implement the CompareUtil
class with a method to compare two image files, as shown in the following code:
package com.secookbook.examples.chapter09; import java.awt.Image; import java.awt.Toolkit; import java.awt.image.PixelGrabber; public class CompareUtil { public enum Result { Matched, SizeMismatch, PixelMismatch }; public static Result CompareImage(String baseFile, String actualFile) { Result compareResult = Result.PixelMismatch; Image baseImage = Toolkit.getDefaultToolkit().getImage(baseFile); Image actualImage = Toolkit.getDefaultToolkit().getImage(actualFile); try { PixelGrabber baseImageGrab = new PixelGrabber(baseImage, 0, 0, -1, -1, false); PixelGrabber actualImageGrab = new PixelGrabber(actualImage, 0, 0, -1, -1, false); int[] baseImageData = null; int[] actualImageData = null; if (baseImageGrab.grabPixels()) { int width = baseImageGrab.getWidth(); int height = baseImageGrab.getHeight(); baseImageData = new int[width * height]; baseImageData = (int[]) baseImageGrab.getPixels(); } if (actualImageGrab.grabPixels()) { int width = actualImageGrab.getWidth(); int height = actualImageGrab.getHeight(); actualImageData = new int[width * height]; actualImageData = (int[]) actualImageGrab.getPixels(); } if ((baseImageGrab.getHeight() != actualImageGrab.getHeight()) || (baseImageGrab.getWidth() != actualImageGrab.getWidth())) compareResult = Result.SizeMismatch; else if (java.util.Arrays.equals(baseImageData, actualImageData)) compareResult = Result.Matched; } catch (Exception e) { e.printStackTrace(); } return compareResult; } }
The CompareUtil
class uses the java.awt.Image
namespace to work with images. The CompareImage()
method takes the path of the base file and the actual file as an argument. It then retrieves these images to the Image
class:
Image baseImage = Toolkit.getDefaultToolkit().getImage(baseFile); Image actualImage = Toolkit.getDefaultToolkit().getImage(actualFile);
Finally, it uses the PixelGrabber
class to get the pixels from these images to an array, as shown in the following code:
PixelGrabber baseImageGrab = new PixelGrabber(baseImage, 0, 0, -1, -1, false); PixelGrabber actualImageGrab = new PixelGrabber(actualImage, 0, 0, -1, -1, false); int[] baseImageData = null; int[] actualImageData = null; if(baseImageGrab.grabPixels()) { int width = baseImageGrab.getWidth(); int height = baseImageGrab.getHeight(); baseImageData = new int[width * height]; baseImageData = (int[])baseImageGrab.getPixels(); } if(actualImageGrab.grabPixels()) { int width = actualImageGrab.getWidth(); int height = actualImageGrab.getHeight(); actualImageData = new int[width * height]; actualImageData = (int[])actualImageGrab.getPixels(); }
The images are first tested for size mismatch, and then for pixel mismatch, using the following code:
if ((baseImageGrab.getHeight() != actualImageGrab.getHeight()) || (baseImageGrab.getWidth() != actualImageGrab.getWidth())) compareResult = Result.SizeMismatch; else if(java.util.Arrays.equals(baseImageData, actualImageData)) compareResult = Result.Matched;
The following code is a sample test, comparing the layout of the application being tested with a base layout captured from an earlier release:
package com.secookbook.examples.chapter09; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.*; import org.apache.commons.io.FileUtils; import org.junit.*; import static org.junit.Assert.*; import java.io.File; public class BmiCalculatorTest { private WebDriver driver; @Before public void setUp() throws Exception { // Create a new instance of the Firefox driver driver = new FirefoxDriver(); } @Test public void testBmiCalculatorLayout() throws Exception { String scrFile = "c:\screenshot.png"; String baseScrFile = "c:\baseScreenshot.png"; // Open the BMI Calculator Page and get a Screen Shot of Page into a // File driver.get("http://dl.dropbox.com/u/55228056/bmicalculator.html"); File screenshotFile = ((TakesScreenshot) driver) .getScreenshotAs(OutputType.FILE); FileUtils.copyFile(screenshotFile, new File(scrFile)); // Verify baseline image with actual image assertEquals(CompareUtil.Result.Matched, CompareUtil.CompareImage(baseScrFile, scrFile)); } @After public void tearDown() throws Exception { // Close the browser driver.quit(); } }
The following code is the C# implementation of CompareUtil
. You can use this class for Selenium tests created with .NET bindings:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; using System.Drawing.Imaging; namespace CompareUtil { public class CompareUtil { public enum Result { Matched, SizeMismatch, PixelMismatch }; public static Result CompareImage(string baseFile, string actualFile) { Result result = Result.Matched; Bitmap baseBmp = (Bitmap)Image.FromFile(baseFile); Bitmap actBmp = (Bitmap)Image.FromFile(actualFile); if (baseBmp.Size != actBmp.Size) result = Result.SizeMismatch; else { int height = Math.Min(baseBmp.Height, actBmp.Height); int width = Math.Min(baseBmp.Width, actBmp.Width); bool are_identical = true; for (int x = 0; x <= width - 1; x++) { for (int y = 0; y <= height - 1; y++) { if (baseBmp.GetPixel(x, y).Equals(actBmp.GetPixel(x, y))) { } else { are_identical = false; } } } if (are_identical == true) result = Result.Matched; else result = Result.PixelMismatch; } return result; } } }
18.118.142.250