在本文中,我将向您介绍如何使用ImageMagick,Selenium Webdriver和AShot进行视觉测试自动化。这个工具和框架组合是完全开源的,当您成功完成设置时,您可以开始无需任何费用就可以对它们进行可视化测试。
首先,我想描述这些工具:
Selenium Webdriver:我们将使用webdriver导航,查询和操作网站。
ImageMagick: ImageMagick是我们的图像处理和比较工具。
链接:http://www.imagemagick.org/script/index.php
纯JAVA界面(im4java):http : //im4java.sourceforge.net/
AShot: AShot是我们的Webdriver Screenshot实用工具。我们将使用AShot截图截图。它由 Yandex及其开源开发。
链接:https://github.com/yandex-qatools/ashot
逐步安装
步骤1:Selenium Webdriver
如果您不知道如何开始使用Selenium Webdriver,请先阅读本文。
第2步:Visual Studio 2013的Visual C ++可再发行组件包
转到此链接:https : //www.microsoft.com/en-us/download/details.aspx?id=40784并安装它。
第3步:ImageMagick
转至http://www.imagemagick.org/script/binary-releases.php并安装Windows Binary Release,在安装期间选择所有选项并将其安装目录位置设置为系统路径。
选择所有选项非常重要。
如何为ImageMagick和Selenium设置项目
测试场景:
- 打开www.kariyer.net
- 添加顶部横幅Cookie不看顶部横幅。
- 如果存在,关闭弹出窗口
- 关闭横幅
- 取消隐藏Uzman Photo的文字区域(“ 21.923???II”部分)
- 悬停在主页上的“UZMAN”部分。
- 等待2秒钟完成图像(CSS)动画。
- 截取此元素的动画照片。
- 在第一次运行时,将它保存到ScreenShots> $ Test_Name文件夹中作为uzmanBaseline.png和uzmanActual.png。
- 第二次运行时,更新uzmanActual.png,并将其与uzmanBaseline.png进行比较,并将差异作为uzmanDiff.png
- 把所有的差异放在“差异”文件夹中。
- 验证他们是否通过了类似的测试。如果没有测试失败。
项目设置:
打开IntelliJ,然后点击文件 - >新建 - >项目 - > Maven
然后,将GroupId和ArtifactId填充为KariyerVisualTest
单击下一步,然后为该项目命名为KariyerVisualTest,然后单击下一步。
之后,我们应该修改我们的pom.xml
始终从https://mvnrepository.com检查库最新版本
对于硒:
XHTML
1
2
3
4
5
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.0.1</version>
</dependency>
对于AShot:
XHTML
<dependency>
<groupId>ru.yandex.qatools.ashot</groupId>
<artifactId>ashot</artifactId>
<version>1.5.3</version>
</dependency>
对于IM4Java:
XHTML
<dependency>
<groupId>org.im4java</groupId>
<artifactId>im4java</artifactId>
<version>1.4.0</version>
</dependency>
对于TestNG:
XHTML
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.10</version>
</dependency>
测试代码
在下面的代码中,我尝试写出详细的评论。如果您遇到麻烦,请随时添加评论。我会尽快回复你的问题。
BaseTest类
KariyerVisualTest .java
Java
import com.google.common.io.Files;
import org.apache.commons.io.FileUtils;
import org.im4java.core.CompareCmd;
import org.im4java.core.IMOperation;
import org.im4java.process.ProcessStarter;
import org.im4java.process.StandardStream;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import ru.yandex.qatools.ashot.AShot;
import ru.yandex.qatools.ashot.Screenshot;
import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
/**
* Created by onurb on 06-Feb-17.
*/
public class BaseTest {
public WebDriver driver;
public WebDriverWait wait;
public JavascriptExecutor js;
//JSWaiter object
JSWaiter jsWaiter;
//Test name
public String testName;
//Test Screenshot directory
public String testScreenShotDirectory;
//URL of the test website
public String url = "http://www.kariyer.net";
//Main Directory of the test code
public String currentDir = System.getProperty("user.dir");
//Main screenshot directory
public String parentScreenShotsLocation = currentDir + "\\ScreenShots\\";
//Main differences directory
public String parentDifferencesLocation = currentDir + "\\Differences\\";
//Element screenshot paths
public String baselineScreenShotPath;
public String actualScreenShotPath;
public String differenceScreenShotPath;
//Image files
public File baselineImageFile;
public File actualImageFile;
public File differenceImageFile;
public File differenceFileForParent;
//Setup Driver
@BeforeClass
public void setupTestClass() throws IOException {
//Declare Firefox driver
driver = new ChromeDriver();
//Maximize the browser
driver.manage().window().maximize();
//Declare a 10 seconds wait time
wait = new WebDriverWait(driver,10);
//JS Executor
js = (JavascriptExecutor) driver;
//JSWaiter
jsWaiter = new JSWaiter(wait);
//Create screenshot and differences folders if they are not exist
createFolder(parentScreenShotsLocation);
createFolder(parentDifferencesLocation);
//Clean Differences Root Folder
File differencesFolder = new File(parentDifferencesLocation);
FileUtils.cleanDirectory(differencesFolder);
//Go to URL
driver.navigate().to(url);
//Add Cookie for top banner
addCookieforTopBanner();
}
@BeforeMethod
public void setupTestMethod (Method method) {
//Get the test name to create a specific screenshot folder for each test.
testName = method.getName();
System.out.println("Test Name: " + testName + "\n");
//Create a specific directory for a test
testScreenShotDirectory = parentScreenShotsLocation + testName + "\\";
createFolder(testScreenShotDirectory);
//Declare element screenshot paths
//Concatenate with the test name.
declareScreenShotPaths(testName+"_Baseline.png", testName+"_Actual.png", testName + "_Diff.png");
}
//Add Cookie not to see top banner animation
public void addCookieforTopBanner () {
//Get Next Month Last Date for cookie expiration
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MONTH, 1);
calendar.set(Calendar.DATE, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
Date nextMonthLastDay = calendar.getTime();
//Create/Build a cookie
Cookie topBannerCloseCookie = new Cookie.Builder("AA-kobiBannerClosed","4") //Name & value pair of the cookie
.domain("www.kariyer.net") //Domain of the cookie
.path("/") //Path of the cookie
.expiresOn(nextMonthLastDay) //Expiration date
.build(); //Finally build it with .build() call
//Add a cookie
driver.manage().addCookie(topBannerCloseCookie);
}
//Create Folder Method
public void createFolder (String path) {
File testDirectory = new File(path);
if (!testDirectory.exists()) {
if (testDirectory.mkdir()) {
System.out.println("Directory: " + path + " is created!" );
} else {
System.out.println("Failed to create directory: " + path);
}
} else {
System.out.println("Directory already exists: " + path);
}
}
//Close popup if exists
public void handlePopup(String selector) throws InterruptedException {
jsWaiter.waitJS();
List<WebElement> popup = driver.findElements(By.cssSelector(selector));
if(!popup.isEmpty()){
popup.get(0).click();
sleep(200);
}
}
//Close Banner
public void closeBanner () {
jsWaiter.waitJS();
List<WebElement> banner = driver.findElements(By.cssSelector("body > div.kobi-head-banner > div > a"));
if (!banner.isEmpty()) {
banner.get(0).click();
//Wait for 2 second for closing banner
sleep(2000);
}
}
//Unhide an Element with JSExecutor
public void unhideElement (String unhideJS) {
js.executeScript(unhideJS);
jsWaiter.waitJS();
sleep(200);
}
//Move to Operation
public void moveToElement (WebElement element){
jsWaiter.waitJS();
Actions actions = new Actions(driver);
jsWaiter.waitJS();
sleep(200);
actions.moveToElement(element).build().perform();
}
//Take Screenshot with AShot
public Screenshot takeScreenshot (WebElement element) {
//Take screenshot with Ashot
Screenshot elementScreenShot = new AShot().takeScreenshot(driver, element);
/*Screenshot elementScreenShot = new AShot()
.coordsProvider(new WebDriverCoordsProvider())
.takeScreenshot(driver,element);*/
//Print element size
String size = "Height: " + elementScreenShot.getImage().getHeight() + "\n" +
"Width: " + elementScreenShot.getImage().getWidth() + "\n";
System.out.print("Size: " + size);
return elementScreenShot;
}
//Write
public void writeScreenshotToFolder (Screenshot screenshot, File imageFile) throws IOException {
ImageIO.write(screenshot.getImage(), "PNG", imageFile);
}
//Screenshot paths
public void declareScreenShotPaths (String baseline, String actual, String diff) {
//BaseLine, Actual, Difference Photo Paths
baselineScreenShotPath = testScreenShotDirectory + baseline;
actualScreenShotPath = testScreenShotDirectory + actual;
differenceScreenShotPath = testScreenShotDirectory + diff;
//BaseLine, Actual Photo Files
baselineImageFile = new File(baselineScreenShotPath);
actualImageFile = new File(actualScreenShotPath);
differenceImageFile = new File (differenceScreenShotPath);
//For copying difference to the parent Difference Folder
differenceFileForParent = new File (parentDifferencesLocation + diff);
}
//ImageMagick Compare Method
public void compareImagesWithImageMagick (String expected, String actual, String difference) throws Exception {
// This class implements the processing of os-commands using a ProcessBuilder.
// This is the core class of the im4java-library where all the magic takes place.
ProcessStarter.setGlobalSearchPath("C:\\Program Files\\ImageMagick-7.0.4-Q16");
// This instance wraps the compare command
CompareCmd compare = new CompareCmd();
// Set the ErrorConsumer for the stderr of the ProcessStarter.
compare.setErrorConsumer(StandardStream.STDERR);
// Create ImageMagick Operation Object
IMOperation cmpOp = new IMOperation();
//Add option -fuzz to the ImageMagick commandline
//With Fuzz we can ignore small changes
cmpOp.fuzz(10.0);
//The special "-metric" setting of 'AE' (short for "Absolute Error" count), will report (to standard error),
//a count of the actual number of pixels that were masked, at the current fuzz factor.
cmpOp.metric("AE");
// Add the expected image
cmpOp.addImage(expected);
// Add the actual image
cmpOp.addImage(actual);
// This stores the difference
cmpOp.addImage(difference);
try {
//Do the compare
System.out.println ("Comparison Started!");
compare.run(cmpOp);
System.out.println ("Comparison Finished!");
}
catch (Exception ex) {
System.out.print(ex);
System.out.println ("Comparison Failed!");
//Put the difference image to the global differences folder
Files.copy(differenceImageFile,differenceFileForParent);
throw ex;
}
}
//Compare Operation
public void doComparison (Screenshot elementScreenShot) throws Exception {
//Did we capture baseline image before?
if (baselineImageFile.exists()){
//Compare screenshot with baseline
System.out.println("Comparison method will be called!\n");
System.out.println("Baseline: " + baselineScreenShotPath + "\n" +
"Actual: " + actualScreenShotPath + "\n" +
"Diff: " + differenceScreenShotPath);
//Try to use IM4Java for comparison
compareImagesWithImageMagick(baselineScreenShotPath, actualScreenShotPath, differenceScreenShotPath);
} else {
System.out.println("BaselineScreenshot is not exist! We put it into test screenshot folder.\n");
//Put the screenshot to the specified folder
ImageIO.write(elementScreenShot.getImage(), "PNG", baselineImageFile);
}
}
//Sleep Function
public void sleep (int milis) {
Long milliseconds = (long) milis;
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
JSWaiter(用于JS和JQuery同步)
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
/**
* Created by onurb on 06-Feb-17.
*/
public class JSWaiter {
public WebDriverWait wait;
public JSWaiter (WebDriverWait wait) {
this.wait = wait;
}
public void waitJS () {
//Wait for Javascript to load
ExpectedCondition<Boolean> jsLoad = driver -> ((JavascriptExecutor) driver)
.executeScript("return document.readyState").toString().equals("complete");
//JQuery Wait
ExpectedCondition<Boolean> jQueryLoad = driver -> ((Long) ((JavascriptExecutor) driver)
.executeScript("return jQuery.active") == 0);
wait.until(jsLoad);
wait.until(jQueryLoad);
}
}
KariyerVisualTest(测试类)
KariyerVisualTest.java
Java
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.testng.annotations.AfterClass;
import org.testng.annotations.Test;
import ru.yandex.qatools.ashot.Screenshot;
/**
* Created by onurb on 28-Aug-16.
*/
public class KariyerVisualTest extends BaseTest {
@Test
public void kariyerUzmanCssTest () throws Exception {
//Handle popup
handlePopup(".ui-dialog-titlebar-close");
//Close banner
closeBanner();
//Declare UZMAN photo section
WebElement uzmanPhotoSection = driver.findElement(By.cssSelector(".item.uzman>a"));
//Unhide Text (It is Changing A lot)
unhideElement("document.getElementsByClassName('count')[0].style.display='none';");
//Move To Operation
moveToElement(uzmanPhotoSection);
//Wait for 2 second for violet color animation
Thread.sleep(2000);
//Take ScreenShot with AShot
Screenshot uzmanScreenShot = takeScreenshot(uzmanPhotoSection);
//Write actual screenshot to the actual screenshot path
writeScreenshotToFolder(uzmanScreenShot, actualImageFile);
//Do image comparison
doComparison(uzmanScreenShot);
}
//Close Driver
@AfterClass
public void quitDriver() {
driver.quit();
}
}
pom.xml中:
pom.xml
XHTML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>KariyerVisualTest</groupId>
<artifactId>KariyerVisualTest</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.10</version>
</dependency>
<dependency>
<groupId>org.im4java</groupId>
<artifactId>im4java</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>ru.yandex.qatools.ashot</groupId>
<artifactId>ashot</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
</dependencies>
</project>
的testng.xml
testNG.xml
XHTML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Kariyer Visual Automation with IM4JAVA Selenium AShot">
<test name="RunTest" preserve-order="true">
<classes>
<class name="KariyerVisualTest" />
</classes>
</test>
</suite>
GitHub链接https://github.com/swtestacademy/VisualAutomationImageMagickSelenium
检测结果:
第一次运行:
二次运行(正面情况):
第三轮(负面情况):
我也想告诉你失败的案例。我用照片编辑器打开uzmanBaseline并添加一些形状并保存。之后,我重新运行测试,并得到了低于结果。测试失败,并突出显示了无与伦比的部分。
在开始测试之前,我对“uzmanBasline.png”进行了以下修改
然后,我运行测试并得到以下结果: