Notes on Building Java Automation Environment (2)
In Note 1, we have completed the development of a key construction project, xml designated planning test set, data decoupling and allure report generation. Next is:
- Browser driver is started by configuration
- Page element location decoupling, mapping JavaBean locator collection objects through configuration files
- Keyword commands, testing new methods of base classes, providing basic keywords (here for some commonly used methods, subsequent extensions)
- Screen shot of test failure
- Basic dependence
- Note that a project has been built and completed
- Test dependencies to be developed
- Browser-driven Object Acquisition Tool Class
- Locator Object and Locator Initialization and Acquisition Tool Class
- Keyword method development
- Test Failure Screen Listener Class
1. Project structure
Some new directories have been added to Compare Note 1
2. Code development
2.1 Browser Start
Browser startup needs to write a browser driver management class to read the data initialization driver from the xml file to provide static access methods.
2.1.1 driver.xml browser driver profile
<?xml version="1.0" encoding="UTF-8"?>
<!-- driverIndex Identity Acquisition Correspondence and name Nodal index Same browser driver -->
<driver driverIndex="0">
<!-- Google Browser Profile -->
<name value="org.openqa.selenium.chrome.ChromeDriver" index="0">
<!-- name Driver class, value Driver name,{default.driver.path}Will automatically replace the current project src/test/resources -->
<properties>
<property name="webdriver.chrome.driver" value="{default.driver.path}/driver/chromedriver.exe" />
</properties>
<!-- chrome Path -->
<options>
<option type="binary">C:\Program Files (x86)\Google\Chrome\Application\chrome.exe</option>
</options>
</name>
<!-- Firefox Browser Corresponding selenium3.x Version Configuration File -->
<name value="org.openqa.selenium.firefox.FirefoxDriver"
seleniumVersion="3.x" index="1">
<properties>
<property name="SystemProperty.BROWSER_BINARY"
value="C:\Program
Files (x86)\Mozilla Firefox\firefox.exe" />
<property
name="webdriver.gecko.driver"
value="E:/driver/geckodriver.exe" />
</properties>
</name>
<!-- Firefox Browser Corresponding selenium2.x Version Configuration File -->
<name value="org.openqa.selenium.firefox.FirefoxDriver"
seleniumVersion="2.x" index="2">
<properties>
<property name="SystemProperty.BROWSER_BINARY"
value="C:\Program
Files (x86)\Mozilla Firefox\firefox.exe" />
</properties>
</name>
<!--IE Browser Profile -->
<name value="org.openqa.selenium.ie.InternetExplorerDriver"
index="3">
<properties>
<property
name="webdriver.ie.driver"
value="{default.driver.path}\driver\IEDriverServer.exe" />
</properties>
<capabilities>
<!-- name Ability, value The value of ability, type Data types of capability values -->
<capability
name="InternetExplorerDriver.IGNORE_ZOOM_SETTING"
type="boolean"
value="true" />
<capability
name="InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS"
type="boolean"
value="true" />
</capabilities>
</name>
</driver>
2.1.2 WebDriverUtil Driver Management Class
Provide getDriver() to get browser objects.
package per.hao.utils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
public class WebDriverUtil {
private static final Logger log = LoggerFactory.getLogger(WebDriverUtil.class);
/* WebDriver class */
private static Class clazz;
/* WebDriver Object */
private static Object obj ;
/**
* Initialize and retrieve the browser WebDriver object according to driver.xml file
*
* @return WebDriver Browser WebDriver Object
* */
public static WebDriver getDriver() {
Document document = null;
Element driverElement= null;
String driverClassName =null;
SAXReader reader = new SAXReader();
try {
document = reader.read(WebDriverUtil.class.getResourceAsStream("/driver.xml"));
} catch (DocumentException e) {
log.error("read driver.xml failed", e);
}
/** Get the driver class name */
Element rootElement = document.getRootElement();
// driver index
int index = Integer.parseInt(rootElement.attributeValue("driverIndex"));
/** Traversing the name node */
List<Element> driverNameElements = rootElement.elements("name");
for (Element driverNameElement : driverNameElements) {
if (index == Integer.parseInt(driverNameElement.attributeValue("index"))) {
driverClassName = driverNameElement.attributeValue("value");
driverElement = driverNameElement;
}
}
/** Get the driver class */
try {
clazz = Class.forName(driverClassName);
log.info("get class:" + driverClassName);
} catch (ClassNotFoundException e) {
log.error("get class error", e);
}
/**
* Here's parsing the XML system parameters and setting them
*/
Element propertiesElement = driverElement.element("properties");
List<Element> propertyElements = propertiesElement.elements("property");
//Setting System Parameters (driver Path, etc.)
for (Element property : propertyElements) {
System.setProperty(property.attributeValue("name"), formatPath(property.attributeValue("value")));
log.info("set property:" + property.attributeValue("name") + "=" +formatPath(property.attributeValue("value")));
}
//Setting capabilities (ie, you need to set the ability to ignore domain settings and page percentages)
Element capabilitiesElement = driverElement.element("capabilities");
if (capabilitiesElement != null) {
DesiredCapabilities realCapabilities = new DesiredCapabilities();
List<Element> capabilitiesElements = capabilitiesElement.elements("capability");
for (Element capability : capabilitiesElements) {
//Traverse the list of capabilities and assign values to capabilities
if ("boolean".equals(capability.attributeValue("type"))) {
realCapabilities.setCapability(capability.attributeValue("name"),
Boolean.parseBoolean(capability.attributeValue("value")));
} else if ("string".equals(capability.attributeValue("type"))) {
realCapabilities.setCapability(capability.attributeValue("name"),
capability.attributeValue("value"));
}
log.info("set capability:" + capability.attributeValue("name") + "=" + capability.attributeValue("value"));
}
}
/** If chrome sets some properties of chrome */
Element optionsElement = driverElement.element("options");
if (optionsElement != null) {
ChromeOptions chromeOptions = new ChromeOptions();
for (Element optionElement : (List<Element>) optionsElement.elements()) {
if ("binary".equals(optionElement.attributeValue("type"))) {
String binary = formatPath(optionElement.getStringValue());
chromeOptions.setBinary(binary);
log.info("set chrome Binary:" + binary);
}
}
WebDriver driver = new ChromeDriver(chromeOptions);
log.info("get driver succeed:" + driverClassName);
return driver;
}
/*
* Create Driver Objects by Reflection
*/
try {
obj = clazz.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
log.info("get driver succeed:" + driverClassName);
return (WebDriver) obj;
}
/**
* Replace variables that appear in xml that need to be replaced
*
* @param path String Route
*
* @return String Path after replacement
* */
private static String formatPath(String path) {
// chrome is not necessarily installed in the user directory and removed
// if (path.contains("{user.home}")) {
// path = path.replace("{user.home}", System.getProperty("user.home"));
// }
if (path.contains("{default.driver.path}")) {
path = path.replace("{default.driver.path}", "src/test/resources");
}
return path;
}
}
2.2 Locator Acquisition
All elements on the interface are written into xml according to the structure of interface - > elements, which realizes the decoupling of locating interface elements, interface element attributes, waiting time and code.
2.2.1 Locator File Example
<?xml version="1.0" encoding="UTF-8"?> <pages> <! - Baidu Query - > <! - pageName: Page name, page Name is used to switch to the set of locators in this interface for each jump to a new interface in the code, or page Name is used to open the interface, etc. --> <! - url: Look back for the URL of this interface when it is open("pageName") and open it - > <! - defaultTimeOut: Default find element timeout, must be filled in - > <!--<page pageName="" url="https://www.baidu.com/" defaultTimeOut="2">--> <page pageName= "Baidu Home Page" url= "https://www.baidu.com/" defaultTimeOut= "2"> <!--name: The name of the locator. In the code, the locator name is used to specify the elements found by the locator on the operation interface. By: positioning method. Optional id linkText name xpath className cssSelector partialLinkText tagName For the name of the method in the By class, the method that is retrieved and invoked by reflection of this property - > <!-- vanle: --> <! - timeOut: If not filled, default TimeOut of page node is used to find timeout by default, default TimeOut must be filled in - > <!-- <locator name="" by="" value="" timeOut=""/> --> <!-- <locator name="" by="" value="" /> --> <locator name="query box" by="id" value="kw" timeOut="3"/> <locator name="Baidu by"="id" value="su" timeOut="3"/> </page> <! - Zen Way Login Interface - > <page pageName="LoginPage" url="http://192.168.2.3/zentao/user-login.html" defaultTimeOut="2"> <locator name="user name" by="id" value="account" timeOut="3"/> <locator name="password" by="name" value="password"/> <locator name="login" by="id" value="submit" timeOut="3"/> <locator name="Forget password" by="linkText" value="Forget password"/> </page> <! - The first page of Zen Tao - > <page pageName="HomePage" url="http://192.168.2.3/zentao/my/" defaultTimeOut="2"> <locator name="user name" by="xpath" value="/*[@id='userNav']/li/a/span[1]" timeOut="3"/> <locator name="system drop-down box" by="xpath" value="/*[@id='userNav']/li/a"/> <locator name="exit" by="xpath" value="/*[@id='userNav']/li/ul/li[13]/a" timeOut="3"/> </page> </pages>
2.2.2 LocatorInfo Locator Object
package per.hao.beans;
import java.io.Serializable;
/**
* locator Mapping object
*
* */
public class LocatorInfo implements Serializable {
private String name;
private String by;
private String value;
private int timeOut;
public LocatorInfo(String name, String by, String value, int timeOut) {
this.name = name;
this.by = by;
this.value = value;
this.timeOut = timeOut;
}
public void setName(String name) {
this.name = name;
}
public void setBy(String by) {
this.by = by;
}
public void setValue(String value) {
this.value = value;
}
public void setTimeOut(int timeOut) {
this.timeOut = timeOut;
}
public String getName() {
return name;
}
public String getBy() {
return by;
}
public String getValue() {
return value;
}
public int getTimeOut() {
return timeOut;
}
@Override
public String toString() {
return "LocatorInfo{" +
"name='" + name + '\'' +
", by='" + by + '\'' +
", value='" + value + '\'' +
", timeOut=" + timeOut +
'}';
}
}
2.2.3 PageInfo Page Object
package per.hao.beans;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* page Mapping object
* */
public class PageInfo implements Serializable {
private String pageName;
private String url;
private Map<String, LocatorInfo> locatorInfoMap= new HashMap<>();
public PageInfo(String pageName, String url, Map<String, LocatorInfo> locatorInfoMap) {
this.pageName = pageName;
this.url = url;
this.locatorInfoMap = locatorInfoMap;
}
public void setPageName(String pageName) {
this.pageName = pageName;
}
public void setUrl(String url) {
this.url = url;
}
public void setLocatorInfoMap(Map<String, LocatorInfo> locatorInfoMap) {
this.locatorInfoMap = locatorInfoMap;
}
public String getPageName() {
return pageName;
}
public String getUrl() {
return url;
}
public Map<String, LocatorInfo> getLocatorInfoMap() {
return locatorInfoMap;
}
@Override
public String toString() {
return "PageInfo{" +
"pageName='" + pageName + '\'' +
", url='" + url + '\'' +
", locatorInfoMap=" + locatorInfoMap +
'}';
}
}
2.2.4 LocatorUtil Locator Resolution Tool Class
package per.hao.utils;
import org.apache.commons.collections.map.HashedMap;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import per.hao.beans.LocatorInfo;
import per.hao.beans.PageInfo;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class LocatorUtil {
private static final Logger log = LoggerFactory.getLogger(LocatorUtil.class);
private static String filePath;
// Map<filePath, Map<pageName, PageInfo>>
private static Map<String, Map<String, PageInfo>> pageInfoMaps = new HashMap<>();
/**
* Rewrite constructor
*
* @param filePath locator The path of the file under resources
* Relative to the configuration file directory, such as: / locator/locator.xml
* That is, locator.xml in the locator directory under resources
* */
public LocatorUtil(String filePath) {
this.filePath = filePath;
}
/**
* Determine to parse only once
* */
private static void sureInit() {
if (pageInfoMaps.get(filePath) == null) {
loadXML();
}
}
/**
* Parsing locator to locate xml files
* */
private static void loadXML() {
SAXReader saxReader = new SAXReader();
Document document = null;
try {
document = saxReader.read(LocatorUtil.class.getResourceAsStream(filePath));
} catch (DocumentException e) {
log.error("open locator file failed:", e);
}
if (document != null) {
log.info("open locator file succeed:" + filePath);
}
// Page page traversal
Element root = document.getRootElement();
List<Element> pageElements = root.elements("page");
Map<String, PageInfo> pageInfoMap = new HashMap<>();
for (Element pageElement : pageElements) {
String pageName = pageElement.attributeValue("pageName");
String url = pageElement.attributeValue("url");
String defaultTimeOut = pageElement.attributeValue("defaultTimeOut");
// Locator locator traversal
List<Element> locatorElements = pageElement.elements("locator");
Map<String, LocatorInfo> locatorInfoMap = new HashedMap();
for (Element locatorElement : locatorElements) {
String name = locatorElement.attributeValue("name");
String by = locatorElement.attributeValue("by");
String value = locatorElement.attributeValue("value");
String timeOut = locatorElement.attributeValue("timeOut");
if (timeOut == null || "".equals(timeOut)) {
timeOut = defaultTimeOut;
}
locatorInfoMap.put(name,
new LocatorInfo(name, by, value, Integer.parseInt(timeOut)));
}
pageInfoMap.put(pageName, new PageInfo(pageName, url, locatorInfoMap));
}
pageInfoMaps.put(filePath, pageInfoMap);
log.info("parse locator file succeed:" + filePath);
}
/**
* Getting the test interface url
*
* @param filePath locator The path of the file under resources
* Relative to the configuration file directory, such as: / locator/locator.xml
* That is, locator.xml in the locator directory under resources
*
* @param pageName Page name, page node pageName element attribute in locator.xml
*
* @return Page url
* */
public static String getURL(String filePath, String pageName) {
new LocatorUtil(filePath);
sureInit();
String url = LocatorUtil.pageInfoMaps.get(filePath).get(pageName).getUrl();
log.debug("get url:" + url);
return url;
}
/**
* Acquisition locator
*
* @param filePath locator The path of the file under resources
* Relative to the configuration file directory, such as: / locator/locator.xml
* That is, locator.xml in the locator directory under resources
* @param pageName Page name, page node element attribute in locator.xml
* @param name locator Node name Element Attribute in locator name locator.xml
*
* @return Positioner
* */
public static LocatorInfo getLocator(String filePath, String pageName, String name) {
new LocatorUtil(filePath);
sureInit();
LocatorInfo locatorInfo = LocatorUtil.pageInfoMaps
.get(filePath)
.get(pageName)
.getLocatorInfoMap().get(name);
log.debug("get locator:" + locatorInfo);
return locatorInfo;
}
}
2.2.5 LocatorSource Locator File Source Annotation
package per.hao.annotations;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LocatorSource {
/**
* locator The path of the file under resources
* Relative to the configuration file directory, such as: / locator/locator.xml
* That is, locator.xml in the locator directory under resources
* */
String filePath();
}
2.2.6 Testing LocatorUtil Method
2.3 Improvement of Test Base Class
- Before adding test set to test base class, the driver is acquired through Web Driver Util, and the test set runs to clean up the running environment.
- Add the getWebElement method to locate the element according to the locator file specified by the current test method LocatorSource annotation.
- Add the internal class GetLocatorFilePath to get the LocatorSource annotation of the current running method, return the path of the filePath annotation, and use it to get elements as getWebElement parameters.
- Perfect browser operation method for inheritance class calls.
2.3.1 BaseTester Test Base Class
package per.hao;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.ITestNGMethod;
import org.testng.Reporter;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.DataProvider;
import per.hao.annotations.DataSource;
import per.hao.annotations.LocatorSource;
import per.hao.beans.LocatorInfo;
import per.hao.utils.DataSourceType;
import per.hao.utils.ExcelReader;
import per.hao.utils.LocatorUtil;
import per.hao.utils.WebDriverUtil;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.regex.Matcher;
public class BaseTester<T> {
public static final Logger log =
LoggerFactory.getLogger(BaseTester.class);
/** driver */
public static WebDriver driver;
/** Current locator pointer to PageInfo's pageName */
private static String pageName;
/** Browser Navigation Bar Object, Encapsulation Navigation Bar Method */
private static WebDriver.Navigation navigation;
/**
* Test Set Initialization Before Start
* */
@BeforeSuite
protected void beforeSuit() {
driver = WebDriverUtil.getDriver();
// window maximizing
driver.manage().window().maximize();
navigation = driver.navigate();
}
/**
* Post-operation of test set
* */
@AfterSuite
protected void afterSuit() {
driver.quit();
}
//Browser Management - ---------------------------------------------------------------------------------------------------------------------------------------------------------
/**
* Empty cookies
* */
protected void deleteAllCookies() {
driver.manage().deleteAllCookies();
}
// ------------------------------------------- assertion - ---------------------------------------------------------------------------------------------------------------------
/**
* Determine whether expected contains actual
*
* @param expected text
* @param actural text
* */
protected void assertTextContain(String expected, String actural) {
Assert.assertTrue(expected.contains(actural),
expected + " [not contain] " + actural);
}
/**
* Judging whether expected is equal to actual
*
* @param expected T expected
* @param actural T actural
* */
public void assertTextEqual(T expected, T actural) {
Assert.assertEquals(expected, actural);
}
/**
* Judge whether it is true
*
* @param b Parametric b
* */
public void assertTrue(boolean b) {
Assert.assertTrue(b);
}
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/**
* Get the title title title of the page
*
* @return String
* */
protected String getTitle() {
return driver.getTitle();
}
/**
* Get the text content of the locator located to the element
*
* @param locatorName locator Node name Element Attribute in locator name locator.xml
*
* @return String
* */
protected String getText(String locatorName) {
return getWebElement(locatorName).getText();
}
/**
* Gets whether the locator locates the element to be checked
*
* @param locatorName locator Node name Element Attribute in locator name locator.xml
*
* @return boolean
* */
protected boolean isSelected(String locatorName) {
return getWebElement(locatorName).isSelected();
}
// The basic operation of elements
/**
* WebElement Locate and click according to the locator
*
* @param locatorName locator Node name Element Attribute in locator name locator.xml
* */
protected void click(String locatorName) {
getWebElement(locatorName).click();
}
/**
* WebElement Locate and enter the specified content according to the locator
*
* @param locatorName locator Node name Element Attribute in locator name locator.xml
* @param input Input content
* */
protected void input(String locatorName, String input) {
getWebElement(locatorName).sendKeys(input);
}
/**
* WebElement Locate and empty according to locator
*
* @param locatorName locator Node name Element Attribute in locator name locator.xml
* */
protected void clear(String locatorName) {
getWebElement(locatorName).clear();
}
// The basic operation of navigation bar
/**
* navigation Browser Back Operation
* */
protected void back() {
navigation.back();
}
/**
* navigation Browser Forward Operation
* */
protected void forward() {
navigation.forward();
}
/**
* navigation Browser refresh operation
* */
protected void refresh() {
navigation.refresh();
}
/**
* navigation Open the specified page
*
* @param pageName Page name, page node pageName element attribute in locator.xml
* */
protected void open(String pageName) {
String url =
LocatorUtil.getURL(new GetLocatorFilePath().invok().getFilePath(), pageName);
go(url);
}
/**
* navigation Open the specified url
*
* @param url Connection string
* */
protected void go(String url) {
navigation.to(url);
}
/**
* Sleep schedule
*
* @param millis Millisecond
* */
protected void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
log.error("sleep error", e);
}
}
/**
* Move the locator pointer to the specified interface set
* */
protected void locate(String pageName) {
this.pageName = pageName;
}
/**
* Get interface elements based on locator name
*
* @param locatorName Locator name locator.xml locator node name attribute
*
* @return WebElement
* */
protected WebElement getWebElement(String locatorName) {
String filePath = new GetLocatorFilePath().invok().getFilePath();
return getWebElement(filePath, locatorName);
}
/**
* According to the location file's path and page name, the locator name obtains the interface elements.
*
* @param filePath locator The path of the file under resources
* Relative to the configuration file directory, such as: / locator/locator.xml
* That is, locator.xml in the locator directory under resources
*
* @param locatorName Locator name locator.xml locator node name attribute
*
* @return WebElement
* */
protected WebElement getWebElement(String filePath, String locatorName) {
LocatorInfo locator = LocatorUtil.getLocator(filePath, pageName, locatorName);
String byMethodName = locator.getBy();
String value = locator.getValue();
int timeOut = locator.getTimeOut();
Class<By> byClass = By.class;
Method declaredMethod;
try {
declaredMethod = byClass.getDeclaredMethod(byMethodName, String.class);
By by = (By) declaredMethod.invoke(null, value);
WebDriverWait wait = new WebDriverWait(driver, timeOut);
WebElement until = wait.until(new ExpectedCondition<WebElement>() {
public WebElement apply(WebDriver input) {
return input.findElement(by);
}
});
return until;
} catch (NoSuchMethodException e) {
log.error("locator by may be error in " + locatorName, e);
} catch (IllegalAccessException e) {
log.error("", e);
} catch (InvocationTargetException e) {
log.error("", e);
}
return null;
}
/**
* Internal tool class to get locator filePath in LocatorSource annotations
* */
private class GetLocatorFilePath {
private String filePath;
ITestNGMethod iTestNGMethod = Reporter.getCurrentTestResult().getMethod();
Method method = iTestNGMethod.getMethod();
LocatorSource locatorSource = method.getAnnotation(LocatorSource.class);
/**
* Initialization
* */
public GetLocatorFilePath invok() {
filePath = locatorSource.filePath();
return this;
}
/**
* Get the locator filePath in the LocatorSource annotation
* */
public String getFilePath() {
return filePath;
}
}
/**
* Data Provision Common Interface
* */
@DataProvider(name = "getData")
public static Iterator<Object[]> getData(Method method) {
DataSource dataSource = null;
/** Data Source Annotation Existence Judgment */
if (method.isAnnotationPresent(DataSource.class)) {
dataSource = method.getAnnotation(DataSource.class);
} else {
log.error("Not specified@DataSource Annotations are initialized dataProvider");
}
/** Returns the corresponding data iterator according to the data source type */
if (DataSourceType.CSV
.equals(dataSource.dataSourceType())) {
// CSVReader
} else if (DataSourceType.POSTGRESQL
.equals(dataSource.dataSourceType())) {
// PostgresqlReader
}
/* Read excel by default */
// By name
if (!"".equals(dataSource.name())) {
return ExcelReader.getDataByName(
dealFilePath(dataSource.filePath()), dataSource.name());
// According to anchor point
} else if (!"".equals(dataSource.locate())) {
return ExcelReader.getDataByLocate(
dealFilePath(dataSource.filePath()), dataSource.sheetName(), dataSource.locate());
// Read the entire sheet page
} else {
return ExcelReader.getDataBySheetName(
dealFilePath(dataSource.filePath()), dataSource.sheetName());
}
}
/**
* If only the filename exists, splice the default read directory, otherwise use the specified path
*
* @param filePath File path
* */
private static String dealFilePath(String filePath) {
if (!filePath.matches(".*[/\\\\].*")) {
filePath = "src/test/resources/data/" + filePath;
}
return new File(filePath.replaceAll("[/\\\\]+",
Matcher.quoteReplacement(File.separator))).getAbsolutePath();
}
}
2.4 Failure Use Case Screenshot
2.4.1 TestFaildListener use case screenshot listener class
The screenshot covers the onTestFailure method of the TestListener Adapter. When the test fails, the screenshot is taken and added as an attachment. The attachment is added using Attachment, the annotation method of Allure. The detailed usage can be seen as follows: TesNG Official Document,Allure official document
package per.hao.listener;
import io.qameta.allure.Attachment;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter;
import per.hao.BaseTester;
public class TestFaildListener extends TestListenerAdapter {
@Override
public void onTestFailure(ITestResult iTestResult) {
screenShot();
}
/**
* Screenshot and add as attachment
*
* @return byte[]Enclosure
* */
@Attachment(value = "Page screenshot",type = "image/png")
public byte[] screenShot() {
return ((TakesScreenshot) BaseTester.driver).getScreenshotAs(OutputType.BYTES);
}
}
2.4.2 TesNG.xml to add listeners
<!-- Screenshot of failed use cases -->
<listener class-name="per.hao.listener.TestFaildListener"/>
3. Documents need to be modified
3.1 pom.xml
<?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>per.hao</groupId>
<artifactId>selenium-project-hzhang</artifactId>
<version>1.0.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<allure.version>2.10.0</allure.version>
<java.version>1.8</java.version>
<aspectj.version>1.9.2</aspectj.version>
</properties>
<dependencies>
<!-- xml Analysis: https://mvnrepository.com/artifact/dom4j/dom4j -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
<scope>test</scope>
</dependency>
<!-- selenium: https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
<scope>test</scope>
</dependency>
<!-- testNG frame -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
<scope>test</scope>
</dependency>
<!-- allure Reporting dependence -->
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-testng</artifactId>
<version>${allure.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-maven</artifactId>
<version>${allure.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<!-- Log dependency -->
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
<scope>test</scope>
</dependency>
<!-- excel Read plug-in -->
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.0</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<configuration>
<argLine>
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
</argLine>
<!-- Test failure continues to run -->
<testFailureIgnore>true</testFailureIgnore>
<!-- testNG Use Case Set xml Set up -->
<suiteXmlFiles>
<suiteXmlFile>
src/test/resources/testng/testNG.xml
</suiteXmlFile>
</suiteXmlFiles>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
<!-- Building plug-ins, Specified Version and Coding -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
<reporting>
<excludeDefaults>true</excludeDefaults>
<plugins>
<plugin>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-maven</artifactId>
<version>${allure.version}</version>
<configuration>
<reportVersion>${allure.version}</reportVersion>
</configuration>
</plugin>
</plugins>
</reporting>
</project>
3.2 testNG.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="MyProjectSuite" parallel="classes" thread-count="1">
<test verbose="2" preserve-order="true" name="Logon test">
<classes>
<class name="per.hao.cases.zendao.login.LoginTest" />
</classes>
</test>
<test name="Baidu Test">
<classes>
<class name="per.hao.cases.BaiDuExampleTest" />
</classes>
</test>
<listeners>
<!-- Data Source Monitoring(modify@Test Partial configuration in annotations) -->
<listener class-name="per.hao.listener.DataSourceListener"/>
<!-- Screenshot of failed use cases -->
<listener class-name="per.hao.listener.TestFaildListener"/>
</listeners>
</suite>
4. Testing
4.1 Test data
For the two test classes of testNG.xml, the locator file elements used in the test have been put in Locator file example Yes.
- Baidu Query Test
- Logon test
4.2 Test Running
Open the command line under the project root directory:
# 1. Running test
mvn clean test site
# 2. Generating reports
mvn io.qameta.allure:allure-maven:serve
4.3 Test results