maven+selenium+java+testng+jenkins自动化测试
最近在公司搭建了一套基于maven+selenium+java+testng+jenkins的自动化测试框架,免得以后重写记录下
工程目录
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\uFF1A**** \u539F\u6587\uFF1Ahttps://blog.****.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优化测试报告
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();