最近在公司搭建了一套基于maven+selenium+java+testng+jenkins的自动化测试框架,免得以后重写记录下

工程目录

maven+selenium+java+testng+jenkins自动化测试-LMLPHP

pom.xml

<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>Realinsight4.0</groupId>
<artifactId>Realinsight4.0</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Realinsight4.0</name> <dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-server</artifactId>
<version>3.141.59</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version> </dependency>
<dependency>
<groupId>org.uncommons</groupId>
<artifactId>reportng</artifactId>
<version>1.1.4</version>
<exclusions>
<exclusion>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>com.relevantcodes</groupId>
<artifactId>extentreports</artifactId>
<version>2.40.2</version>
</dependency>
<dependency>
<groupId>com.vimalselvam</groupId>
<artifactId>testng-extentsreport</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.17</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
<!--
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.5</version>
<configuration>
<properties>
<property>
<name>usedefaultlisteners</name>
<value>false</value>
</property>
<property>
<name>listener</name>
<value>org.uncommons.reportng.HTMLReporter,org.uncommons.reportng.JUnitXMLReporter</value>
</property>
</properties>
<workingDirectory></workingDirectory> </configuration>
</plugin>
-->
</plugins>
</build> </project>

testng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Realinsight4.0">
<listeners>
<listener class-name="utils.RetryListener" />
<listener class-name="utils.TestngListener" />
<listener class-name="utils.ExtentReporterListener" />
</listeners>
<test name="登陆测试" verbose="10" preserve-order="true">
<classes>
<class name="testcase.login.login"/>
<class name="testcase.login.loginWithParas"/>
<class name="testcase.login.createAccount"/>
<class name="testcase.login.lockAccount"/>
<class name="testcase.login.resetPwd"/>
<class name="testcase.login.logout"/>
</classes>
</test>
<test name="数据集测试" verbose="10" preserve-order="true">
<classes>
<class name="testcase.boardsheet.UploadData"/>
<class name="testcase.boardsheet.AggRegate"/>
<class name="testcase.boardsheet.AppendData"/>
<class name="testcase.boardsheet.CreatBySQL"/>
<class name="testcase.boardsheet.AppendMerge"/>
<class name="testcase.boardsheet.DimensionalityReduction"/>
<class name="testcase.boardsheet.ReplaceData"/>
</classes>
</test>
<test name="仪表板测试" verbose="10" preserve-order="true">
<classes>
<class name="testcase.dashboard.CreateDashBoard"/>
<class name="testcase.dashboard.CreateChart"/>
<class name="testcase.dashboard.ChartOperation"/>
<class name="testcase.dashboard.TextOperation"/>
</classes>
</test>
<test name="刪除数据" verbose="10" preserve-order="true">
<classes>
<class name="testcase.boardsheet.Deleteboardsheet"/>
</classes>
</test>
</suite> <!-- Suite -->

log4j.properties

log4j.rootCategory=INFO, stdout , R

log4j.appender.CONSOLE = org.apache.log4j.ConsoleAppender\u00A0
log4j.appender.Threshold = DEBUG\u00A0
log4j.appender.CONSOLE.Target = System.out\u00A0
log4j.appender.CONSOLE.layout = org.apache.log4j.PatternLayout\u00A0
log4j.appender.CONSOLE.layout.ConversionPattern = [framework] % d - % c -%- 4r [ % t] %- 5p % c % x - % m % n\u00A0 ---------------------
\u4F5C\u8005\uFF1AJXNUleo
\u6765\u6E90\uFF1ACSDN
\u539F\u6587\uFF1Ahttps://blog.csdn.net/m0_37874657/article/details/80536086
\u7248\u6743\u58F0\u660E\uFF1A\u672C\u6587\u4E3A\u535A\u4E3B\u539F\u521B\u6587\u7AE0\uFF0C\u8F6C\u8F7D\u8BF7\u9644\u4E0A\u535A\u6587\u94FE\u63A5\uFF01
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[YG] %p [%t] %C.%M(%L) | %m%n log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=${project}/WEB-INF/logs/app.log
log4j.appender.R.layout=org.apache.log4j.PatternLayout
1log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n log4j.logger.com.neusoft=DEBUG
log4j.logger.com.opensymphony.oscache=ERROR
log4j.logger.net.sf.navigator=ERROR
log4j.logger.org.apache.commons=ERROR
log4j.logger.org.apache.struts=WARN
log4j.logger.org.displaytag=ERROR
log4j.logger.org.springframework=DEBUG
log4j.logger.com.ibatis.db=WARN
log4j.logger.org.apache.velocity=FATAL log4j.logger.com.canoo.webtest=WARN log4j.logger.org.hibernate.ps.PreparedStatementCache=WARN
log4j.logger.org.hibernate=DEBUG
log4j.logger.org.logicalcobwebs=WARN log4j.rootCategory=INFO, stdout , R log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=D:\\logs\\YG.log
log4j.appender.R.layout=org.apache.log4j.PatternLayout
1log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n log4j.logger.com.neusoft=DEBUG
log4j.logger.com.opensymphony.oscache=ERROR
log4j.logger.net.sf.navigator=ERROR
log4j.logger.org.apache.commons=ERROR
log4j.logger.org.apache.struts=WARN
log4j.logger.org.displaytag=ERROR
log4j.logger.org.springframework=DEBUG
log4j.logger.com.ibatis.db=WARN
log4j.logger.org.apache.velocity=FATAL log4j.logger.com.canoo.webtest=WARN log4j.logger.org.hibernate.ps.PreparedStatementCache=WARN
log4j.logger.org.hibernate=DEBUG
log4j.logger.org.logicalcobwebs=WARN

ExtentReporterListener.java

package utils;

import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.ResourceCDN;
import com.aventstack.extentreports.Status;
import com.aventstack.extentreports.model.TestAttribute;
import com.aventstack.extentreports.reporter.ExtentHtmlReporter;
import com.aventstack.extentreports.reporter.configuration.ChartLocation;
import com.aventstack.extentreports.reporter.configuration.Theme;
import org.testng.*;
import org.testng.xml.XmlSuite; import java.io.File;
import java.util.*; public class ExtentReporterListener implements IReporter {
//生成的路径以及文件名
private static final String OUTPUT_FOLDER = "test-output/";
private static final String FILE_NAME = "index.html"; private ExtentReports extent; @Override
public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
init();
boolean createSuiteNode = false;
if(suites.size()>1){
createSuiteNode=true;
}
for (ISuite suite : suites) {
Map<String, ISuiteResult> result = suite.getResults();
//如果suite里面没有任何用例,直接跳过,不在报告里生成
if(result.size()==0){
continue;
}
//统计suite下的成功、失败、跳过的总用例数
int suiteFailSize=0;
int suitePassSize=0;
int suiteSkipSize=0;
ExtentTest suiteTest=null;
//存在多个suite的情况下,在报告中将同一个一个suite的测试结果归为一类,创建一级节点。
if(createSuiteNode){
suiteTest = extent.createTest(suite.getName()).assignCategory(suite.getName());
}
boolean createSuiteResultNode = false;
if(result.size()>1){
createSuiteResultNode=true;
}
for (ISuiteResult r : result.values()) {
ExtentTest resultNode;
ITestContext context = r.getTestContext();
if(createSuiteResultNode){
//没有创建suite的情况下,将在SuiteResult的创建为一级节点,否则创建为suite的一个子节点。
if( null == suiteTest){
resultNode = extent.createTest(r.getTestContext().getName());
}else{
resultNode = suiteTest.createNode(r.getTestContext().getName());
}
}else{
resultNode = suiteTest;
}
if(resultNode != null){
resultNode.getModel().setName(suite.getName()+" : "+r.getTestContext().getName());
if(resultNode.getModel().hasCategory()){
resultNode.assignCategory(r.getTestContext().getName());
}else{
resultNode.assignCategory(suite.getName(),r.getTestContext().getName());
}
resultNode.getModel().setStartTime(r.getTestContext().getStartDate());
resultNode.getModel().setEndTime(r.getTestContext().getEndDate());
//统计SuiteResult下的数据
int passSize = r.getTestContext().getPassedTests().size();
int failSize = r.getTestContext().getFailedTests().size();
int skipSize = r.getTestContext().getSkippedTests().size();
suitePassSize += passSize;
suiteFailSize += failSize;
suiteSkipSize += skipSize;
if(failSize>0){
resultNode.getModel().setStatus(Status.FAIL);
}
resultNode.getModel().setDescription(String.format("Pass: %s ; Fail: %s ; Skip: %s ;",passSize,failSize,skipSize));
}
buildTestNodes(resultNode,context.getFailedTests(), Status.FAIL);
buildTestNodes(resultNode,context.getSkippedTests(), Status.SKIP);
buildTestNodes(resultNode,context.getPassedTests(), Status.PASS);
}
if(suiteTest!= null){
suiteTest.getModel().setDescription(String.format("Pass: %s ; Fail: %s ; Skip: %s ;",suitePassSize,suiteFailSize,suiteSkipSize));
if(suiteFailSize>0){
suiteTest.getModel().setStatus(Status.FAIL);
}
} }
// for (String s : Reporter.getOutput()) {
// extent.setTestRunnerOutput(s);
// } extent.flush();
} private void init() {
//文件夹不存在的话进行创建
File reportDir= new File(OUTPUT_FOLDER);
if(!reportDir.exists()&& !reportDir .isDirectory()){
reportDir.mkdir();
}
ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter(OUTPUT_FOLDER + FILE_NAME);
// 设置静态文件的DNS
//怎么样解决cdn.rawgit.com访问不了的情况
htmlReporter.config().setEncoding("gbk");
htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS); htmlReporter.config().setDocumentTitle("自动化测试报告");
htmlReporter.config().setReportName("自动化测试报告");
htmlReporter.config().setChartVisibilityOnOpen(true);
htmlReporter.config().setTestViewChartLocation(ChartLocation.TOP);
htmlReporter.config().setTheme(Theme.STANDARD);
htmlReporter.config().setCSS(".node.level-1 ul{ display:none;} .node.level-1.active ul{display:block;}");
extent = new ExtentReports();
extent.attachReporter(htmlReporter);
extent.setReportUsesManualConfiguration(true);
} private void buildTestNodes(ExtentTest extenttest, IResultMap tests, Status status) {
//存在父节点时,获取父节点的标签
String[] categories=new String[0];
if(extenttest != null ){
List<TestAttribute> categoryList = extenttest.getModel().getCategoryContext().getAll();
categories = new String[categoryList.size()];
for(int index=0;index<categoryList.size();index++){
categories[index] = categoryList.get(index).getName();
}
} ExtentTest test; if (tests.size() > 0) {
//调整用例排序,按时间排序
Set<ITestResult> treeSet = new TreeSet<ITestResult>(new Comparator<ITestResult>() {
@Override
public int compare(ITestResult o1, ITestResult o2) {
return o1.getStartMillis()<o2.getStartMillis()?-1:1;
}
});
treeSet.addAll(tests.getAllResults());
for (ITestResult result : treeSet) {
Object[] parameters = result.getParameters();
String name="";
//如果有参数,则使用参数的toString组合代替报告中的name
for(Object param:parameters){
name+=param.toString();
}
if(name.length()>0){
if(name.length()>50){
name= name.substring(0,49)+"...";
}
}else{
name = result.getMethod().getMethodName();
}
if(extenttest==null){
test = extent.createTest(name);
}else{
//作为子节点进行创建时,设置同父节点的标签一致,便于报告检索。
test = extenttest.createNode(name).assignCategory(categories);
}
//test.getModel().setDescription(description.toString());
//test = extent.createTest(result.getMethod().getMethodName());
for (String group : result.getMethod().getGroups())
test.assignCategory(group); List<String> outputList = Reporter.getOutput(result);
for(String output:outputList){
//将用例的log输出报告中
test.debug(output);
}
if (result.getThrowable() != null) {
test.log(status, result.getThrowable());
}
else {
test.log(status, "Test " + status.toString().toLowerCase() + "ed");
} test.getModel().setStartTime(getTime(result.getStartMillis()));
test.getModel().setEndTime(getTime(result.getEndMillis()));
}
}
} private Date getTime(long millis) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(millis);
return calendar.getTime();
}
}

OverrideRetry.java

package utils;
import org.testng.IRetryAnalyzer;
import org.testng.ITestResult; public class OverrideRetry implements IRetryAnalyzer {
private int count = 1;
private int max_count = 3; @Override
public boolean retry(ITestResult result) {
System.out.println("执行用例:"+result.getName()+",第"+count+"次失败");
if (count < max_count) {
count++;
return true;
}
return false;
}
}

ParasUtils.java

package utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties; public class ParasUtils {
private String db_url;
private String db_username;
private String db_password;
private String db_tableName;
private String url;
private String username;
private String password;
private String userData;
private String downloadDir;
private String uploadDir;
private String chromePath; public void readParas(){
try {
InputStream inStream = new FileInputStream(new File(System.getProperty("user.dir")+"\\datas\\Paras.properties"));
Properties prop = new Properties();
prop.load(inStream);
setDb_url(prop.getProperty("db_url"));
setDb_username(prop.getProperty("db_username"));
setDb_password(prop.getProperty("db_password"));
setDb_tableName(prop.getProperty("db_tableName"));
setUrl(prop.getProperty("url"));
setUsername(prop.getProperty("username"));
setPassword(prop.getProperty("password"));
setUserData(prop.getProperty("user-data-dir"));
setUploadDir(prop.getProperty("uploadDir"));
setDownloadDir(prop.getProperty("downloadDir"));
setChromePath(prop.getProperty("chromePath")); } catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} public String getUrl() {
readParas();
return url;
} public void setUrl(String url) {
this.url = url;
} public String getUsername() {
readParas();
return username;
} public void setUsername(String username) {
this.username = username;
} public String getPassword() {
readParas();
return password;
} public void setPassword(String password) {
this.password = password;
} public String getUserData() {
readParas();
return userData;
} public void setUserData(String userData) {
this.userData = userData;
} public String getDownloadDir() {
readParas();
return downloadDir;
} public void setDownloadDir(String downloadDir) {
this.downloadDir = downloadDir;
} public String getDb_username() {
return db_username;
} public void setDb_username(String db_username) {
this.db_username = db_username;
} public String getDb_url() {
return db_url;
} public void setDb_url(String db_url) {
this.db_url = db_url;
} public String getDb_password() {
return db_password;
} public void setDb_password(String db_password) {
this.db_password = db_password;
} public String getDb_tableName() {
return db_tableName;
} public void setDb_tableName(String db_tableName) {
this.db_tableName = db_tableName;
} public void setUp() {
// TODO Auto-generated method stub } public String getUploadDir() {
return uploadDir;
} public void setUploadDir(String uploadDir) {
this.uploadDir = uploadDir;
} public String getChromePath() {
return chromePath;
} public void setChromePath(String chromePath) {
this.chromePath = chromePath;
} }

ReadCSV.java

package utils;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List; public class ReadCSV {
public static Object [][] readCSV(String fileName)
throws IOException {
//读取CSV文件的方法
List<Object[]> records = new ArrayList<Object[]>();
String record;
BufferedReader file = new BufferedReader(new InputStreamReader(new FileInputStream(fileName),"UTF-8"));
file.readLine();
while ((record=file.readLine())!=null){
String fields[] = record.split(",");
records.add(fields);
}
file.close(); Object[][] results = new Object[records.size()][];
for (int i=0; i<records.size();i++){
results[i] = records.get(i);
}
return results;
} }

RetryListener.java

package utils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method; import org.testng.IAnnotationTransformer;
import org.testng.IRetryAnalyzer;
import org.testng.annotations.ITestAnnotation; public class RetryListener implements IAnnotationTransformer { public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { IRetryAnalyzer retry = annotation.getRetryAnalyzer();
if (retry == null) {
annotation.setRetryAnalyzer(OverrideRetry.class); // 这个类名一定要和上方的对上 }
}
}

TestngListener.java

package utils;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set; import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.testng.ITestContext;
import org.testng.ITestNGMethod;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter; import common.basic; public class TestngListener extends TestListenerAdapter {
private static Logger logger = Logger.getLogger(TestngListener.class); @Override
public void onTestFailure(ITestResult tr) {
super.onTestFailure(tr);
logger.info(tr.getName() + "Failure");
basic basic=(basic)tr.getInstance();
takeScreenshot(basic.driver);
} @Override
public void onTestSkipped(ITestResult tr) {
super.onTestSkipped(tr);
logger.info(tr.getName() + "Skipped");
basic basic=(basic)tr.getInstance();
takeScreenshot(basic.driver);
} @Override
public void onTestSuccess(ITestResult tr) {
super.onTestSuccess(tr);
logger.info(tr.getName() + "Success");
} @Override
public void onTestStart(ITestResult tr) {
super.onTestStart(tr);
logger.info(tr.getName() + "Start");
} @Override
public void onFinish(ITestContext testContext) {
super.onFinish(testContext);
ArrayList<ITestResult> testsToBeRemoved = new ArrayList<ITestResult>();
Set<Integer> passedTestIds = new HashSet<Integer>();
for (ITestResult passedTest : testContext.getPassedTests()
.getAllResults()) {
logger.info("PassedTests = " + passedTest.getName());
passedTestIds.add(getId(passedTest));
} Set<Integer> failedTestIds = new HashSet<Integer>();
for (ITestResult failedTest : testContext.getFailedTests()
.getAllResults()) {
logger.info("failedTest = " + failedTest.getName());
int failedTestId = getId(failedTest);
if (failedTestIds.contains(failedTestId)
|| passedTestIds.contains(failedTestId)) {
testsToBeRemoved.add(failedTest);
} else {
failedTestIds.add(failedTestId);
}
} for (Iterator<ITestResult> iterator = testContext.getFailedTests()
.getAllResults().iterator(); iterator.hasNext();) {
ITestResult testResult = iterator.next();
if (testsToBeRemoved.contains(testResult)) {
logger.info("Remove repeat Fail Test: " + testResult.getName());
iterator.remove();
}
} } private int getId(ITestResult result) {
int id = result.getTestClass().getName().hashCode();
id = id + result.getMethod().getMethodName().hashCode();
id = id
+ (result.getParameters() != null ? Arrays.hashCode(result
.getParameters()) : 0);
return id;
} private void takeScreenshot(WebDriver driver,String screenPath) {
try {
File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(scrFile, new File(screenPath));
} catch (IOException e) {
System.out.println("Screen shot error: " + screenPath);
}
} public void takeScreenshot(WebDriver driver) {
String screenName = String.valueOf(new Date().getTime()) + ".jpg";
File dir = new File("test-output/snapshot");
if (!dir.exists())
dir.mkdirs();
String screenPath = dir.getAbsolutePath() + "\\" + screenName;
this.takeScreenshot(driver,screenPath);
} }

loginPage.java

package page;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.*; public class loginPage{
//用户名
@FindBy(id = "username")
public WebElement username; //密码
@FindBy(id = "pwd")
public WebElement password; //登录按钮
@FindBy(xpath = "//button[text()='登录' and @class='btn login-btn']")
public WebElement loginButton; //个人中心
@FindBy(xpath = "//li[@class='personal-center nav-info__item']")
public WebElement personalCenter; //个人中心-名称
@FindBy(xpath = "//div[@class='personal-info fl no-border']/div[2]/p[@class='name nowrap']")
public WebElement nameInfo; //账号已休眠提示
@FindBy(xpath = "//div[text()='该账号已休眠,请联系管理员激活' and @class='jquery-notific8-message']")
public WebElement stopUserMessage; //用户名密码错误提示
@FindBy(xpath = "//div[text()='用户名密码错误' and @class='jquery-notific8-message']")
public WebElement wrongPwd; //登录错误次数过多提示
@FindBy(xpath = "//div[text()='您的用户登录错误次数过多,已被锁定,请联系管理员' and @class='jquery-notific8-message']")
public WebElement lockMessage; //解锁成功提示
@FindBy(xpath = "//div[text()='解锁成功' and @class='jquery-notific8-message']")
public WebElement unlockMessage; //重置密码成功提示
@FindBy(xpath = "//div[text()='重置密码成功' and @class='jquery-notific8-message']")
public WebElement resetMessage; //第一次登录修改密码提示
@FindBy(xpath = "//div[text()='您是第一次登录,请修改密码' and @class='jquery-notific8-message']")
public WebElement firstLoginMessage; //创建成功
@FindBy(xpath = "//div[text()='创建成功' and @class='jquery-notific8-message']")
public WebElement createSuccessMessage; //退出按鈕
@FindBy(xpath = "//div[text()='退出' and @class='logout operate-item']")
public WebElement logoutButton; //进入时间
@FindBy(xpath = "//li[@fieldname='进入时间']")
public WebElement time; //时间排序
@FindBy(xpath = "//li[@fieldname='进入时间']/div/div[2]/div/div/div[2]")
public WebElement sortArrow; //登出成功日志记录
@FindBy(xpath = "//tbody/tr[3]/td[contains(text(),'登出成功')]")
public WebElement logoutLogs; //ygtest用户
@FindBy(xpath = "td[@text='ygtest')]")
public WebElement ygtest; //ygtest01用户
@FindBy(xpath = "//tbody/tr/td[contains(text(),'ygtest01')]")
public WebElement ygtest01; //ygtest02用户
@FindBy(xpath = "//tbody/tr/td[contains(text(),'ygtest02')]")
public WebElement ygtest02; //输入关键字搜索
@FindBy(xpath = "//input[@placeholder='输入关键字搜索']")
public WebElement searchByKey; //用户菜单
@FindBy(id="userManage")
public WebElement userManage; //配置管理菜单
@FindBy(id="configManage")
public WebElement configManage; //锁定
@FindBy(xpath = "//i[@class='ygmat-status-lock'and @title='锁定']")
public WebElement lockIcon; //重置密码
@FindBy(xpath = "//i[@class='ygmat-reset cursor-pointer resetPwd-btn mr8'and @title='重置密码']")
public WebElement resetPwd; //新增用户
@FindBy(xpath = "//li[@title='新增用户']")
public WebElement addUser; //用户名
@FindBy(xpath = "//input[@validatename='用户名']")
public WebElement newusername; //显示名
@FindBy(xpath = "//input[@validatename='显示名']")
public WebElement newshowname; //原密码
@FindBy(xpath = "//input[@validatename='原密码']")
public WebElement oldPwd; //新密码
@FindBy(xpath = "//input[@validatename='新密码']")
public WebElement newPwd; //再次输入
@FindBy(xpath = "//input[@validatename='再次输入']")
public WebElement againPwd; //所属组织
@FindBy(xpath = "//div[@class='belong-org clearfix mb10']/div/button")
public WebElement belongOrg; //所属用户组
@FindBy(xpath = "//div[@class='belong-group clearfix']/div/button")
public WebElement belongGroup; //组织
@FindBy(xpath = "//li[@class='folder-item']/p/input")
public WebElement selectGroup; public loginPage(WebDriver driver){
PageFactory.initElements(driver, this);
}
}

basic.java

package common;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.Select;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.Assert; import org.apache.log4j.Logger; import page.*;
import utils.*; public class basic extends ParasUtils{
private static Logger logger=Logger.getLogger(basic.class); public ChromeDriver driver;
public WebDriverWait wait;
public loginPage loginPage;
public commonPage commonPage; //初始化浏览器
public void initBrowser(){
System.setProperty("webdriver.chrome.driver", System.getProperty("user.dir")+"\\datas\\chromedriver2.37.exe");
ChromeOptions options = new ChromeOptions();
options.addArguments("UserDataDir="+this.getUserData());
options.setBinary(this.getChromePath()+"chrome.exe");
driver = new ChromeDriver(options);
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
driver.manage().timeouts().pageLoadTimeout(5, TimeUnit.SECONDS);
logger.info("打开浏览器:"+this.getUrl());
driver.get(this.getUrl());
} //登录
public void login(){
initBrowser();
loginPage=new loginPage(driver);
loginPage.username.sendKeys(this.getUsername());
loginPage.password.sendKeys(this.getPassword());
threadwait(1000);
click(loginPage.loginButton);
logger.info("登录成功");
commonPage=new commonPage(driver);
} //管理员登录
public void login_Manager(){
initBrowser();
loginPage=new loginPage(driver);
loginPage.username.sendKeys("mat");
loginPage.password.sendKeys("1234.abcd");
threadwait(1000);
click(loginPage.loginButton);
logger.info("登录成功");
commonPage=new commonPage(driver);
} public void refreshBrower(){
driver.navigate().refresh();
} //退出
public void logout(){
driver.quit();
logger.info("退出浏览器成功");
} //等待元素可被点击
public void waitFor(WebElement element){
wait=new WebDriverWait(driver, 20);
wait.until(ExpectedConditions.elementToBeClickable(element));
} //等待元素点击
public void click(WebElement element){
try {
waitFor(element);
logger.info("点击"+element.getTagName()+element.getText());
element.click();
} catch (Exception e) {
threadwait(2000);
element.click();
}
} //等待元素点击
public void mouseClick(WebElement element){
Actions actions=new Actions(driver);
logger.info("点击"+element.getText());
try {
actions.contextClick(element);
} catch (Exception e) {
threadwait(2000);
actions.contextClick(element);
}
} //强制等待
public void threadwait(long time){
try {
Thread.sleep(time);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} //模拟键盘双击
public void doubleClick(WebElement element){
waitFor(element);
logger.info("点击"+element.getText());
Actions actions=new Actions(driver);
actions.doubleClick(element).perform();
} //拖拽
public void dragAndDrop(WebElement source,WebElement target){
waitFor(source);
logger.info(source.getText()+"拖拽到"+target.getText());
Actions actions=new Actions(driver);
actions.dragAndDrop(source, target).perform();
} //悬浮
public void hover(WebElement element){
waitFor(element);
logger.info("悬浮"+element.getText());
Actions actions=new Actions(driver);
actions.moveToElement(element).perform();
} //判断元素是否存在
public boolean isExist(WebElement element)
{
try
{
waitFor(element);
element.isDisplayed();
return true;
}
catch (Exception e) {
return false;
}
} //等待元素消失不可见
public boolean waitForDisappear(WebElement element){
wait=new WebDriverWait(driver, 30, 1);
try {
wait.until(ExpectedConditions.invisibilityOf(element));
} catch (Exception e) {
return false;
}
return true;
} public void selectby(WebElement element,int index){
waitFor(element);
Select select=new Select(element);
select.selectByIndex(index);
} public void assertTrue(WebElement element){
wait=new WebDriverWait(driver, 30);
try {
wait.until(ExpectedConditions.elementToBeClickable(element));
} catch (Exception e) {
}
Assert.assertTrue(element.isDisplayed());
} //切换到某个元素所在的iframe下
public void switchToIframe(WebElement ele){
driver.switchTo().frame(ele);
} //切换回默认frame
public void switchToDefaultContent(){
driver.switchTo().defaultContent();
} //滚动到顶
public void scrollToTop(){
((JavascriptExecutor)driver).executeScript("document.documentElement.scrollTop=0");
} //滚动到底
public void scrollToBottom(){
((JavascriptExecutor)driver).executeScript("document.documentElement.scrollTop=10000");
} // @Override
// @BeforeClass
// public void setUp(){
// System.setProperty("webdriver.chrome.driver", System.getProperty("user.dir")+"\\datas\\chromedriver2.37.exe");
// driver=new ChromeDriver();
// driver.manage().window().maximize();
// driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
// driver.get(this.getUrl());
// } }

loginwithParas.java

package testcase.login;

import org.apache.log4j.Logger;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test; import common.basic;
import page.loginPage;
import utils.ReadCSV; /**
* 用例名:用戶登录
* 用例编号:AT-001
*/
public class loginWithParas extends basic {
private static Logger logger = Logger.getLogger(loginWithParas.class); @DataProvider(name = "loginData")
public static Object[][] words() throws Exception {
return ReadCSV.readCSV(System.getProperty("user.dir") + "\\datas\\loginData.csv");
} @Test(dataProvider="loginData")
public void loginWithPara(String username, String password, String result) {
logger.info(username+" "+password+" "+result); initBrowser();
loginPage=new loginPage(driver);
loginPage.username.sendKeys(username);
loginPage.password.sendKeys(password);
threadwait(1000);
click(loginPage.loginButton); //验证已停用账号
if (result.contains("停用")) {
Assert.assertTrue(isExist(loginPage.stopUserMessage));
//验证已停用账号
} else if(result.contains("用户名密码错误")){
Assert.assertTrue(isExist(loginPage.wrongPwd));
} else {
//验证其他不同类型帐号
threadwait(1000);
click(loginPage.personalCenter);
threadwait(1000);
logger.info("预期值:"+result);
logger.info("实际值:"+loginPage.nameInfo.getText());
Assert.assertTrue(loginPage.nameInfo.getText().contains(result));
} logout();
}
}

extentsreport优化测试报告

maven+selenium+java+testng+jenkins自动化测试-LMLPHP

NoSuchElementException:检查页面元素的定位表达式是否正确,或尝试其他定位方式;查看页面是否加载延迟,设置等待时间;

NoSuchFrameException :检查元素是否frame里,是否已切换到元素的frame下,或切换回default content

ElementNotVisibleException:检查元素是否存在不可见属性的元素,可借助Javascript实现元素操作;检查是否操作速度过快,页面没加载出来

Cannot focus element:检查是否sendkeys非input元素,可用Action后focus输入

Actions actions = new Actions(driver);
actions.moveToElement(element);
actions.click();
actions.sendKeys(text);
actions.build().perform();

04-25 12:29