使用ImageMagick和Selenium Webdriver进行自动化视觉测试
Posted 京鸿智武
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用ImageMagick和Selenium Webdriver进行自动化视觉测试相关的知识,希望对你有一定的参考价值。
在本文中,我将向您介绍如何使用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
1 2 3 4 5 |
<dependency> <groupId>ru.yandex.qatools.ashot</groupId> <artifactId>ashot</artifactId> <version>1.5.3</version> </dependency> |
对于IM4Java:
XHTML
1 2 3 4 5 |
<dependency> <groupId>org.im4java</groupId> <artifactId>im4java</artifactId> <version>1.4.0</version> </dependency> |
对于TestNG:
XHTML
1 2 3 4 5 |
<dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>6.10</version> </dependency> |
测试代码
在下面的代码中,我尝试写出详细的评论。如果您遇到麻烦,请随时添加评论。我会尽快回复你的问题。
BaseTest类
KariyerVisualTest .java
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 |
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同步)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
<?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
1 2 3 4 5 6 7 8 9 10 |
<?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”进行了以下修改
然后,我运行测试并得到以下结果:
网址:www.kingoftech.cn
以上是关于使用ImageMagick和Selenium Webdriver进行自动化视觉测试的主要内容,如果未能解决你的问题,请参考以下文章