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

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

工程目录

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

 

pom.xml

maven+selenium+java+testng+jenkins自动化测试maven+selenium+java+testng+jenkins自动化测试
<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>
View Code

testng.xml

maven+selenium+java+testng+jenkins自动化测试maven+selenium+java+testng+jenkins自动化测试
<?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 -->
View Code

log4j.properties

maven+selenium+java+testng+jenkins自动化测试maven+selenium+java+testng+jenkins自动化测试
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
View Code

ExtentReporterListener.java

maven+selenium+java+testng+jenkins自动化测试maven+selenium+java+testng+jenkins自动化测试
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();
    }
}
View Code

OverrideRetry.java

maven+selenium+java+testng+jenkins自动化测试maven+selenium+java+testng+jenkins自动化测试
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;
    }
}
View Code

ParasUtils.java

maven+selenium+java+testng+jenkins自动化测试maven+selenium+java+testng+jenkins自动化测试
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;
    }
    
}
View Code

ReadCSV.java

maven+selenium+java+testng+jenkins自动化测试maven+selenium+java+testng+jenkins自动化测试
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;
        }
     
}
View Code

RetryListener.java

maven+selenium+java+testng+jenkins自动化测试maven+selenium+java+testng+jenkins自动化测试
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); // 这个类名一定要和上方的对上

        }
    }
}
View Code

TestngListener.java

maven+selenium+java+testng+jenkins自动化测试maven+selenium+java+testng+jenkins自动化测试
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);
    }
    
}
View Code

 

loginPage.java

maven+selenium+java+testng+jenkins自动化测试maven+selenium+java+testng+jenkins自动化测试
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);
    }
}
View Code

basic.java

maven+selenium+java+testng+jenkins自动化测试maven+selenium+java+testng+jenkins自动化测试
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());
//    }
    

}
View Code

loginwithParas.java

maven+selenium+java+testng+jenkins自动化测试maven+selenium+java+testng+jenkins自动化测试
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();
  }
}
View Code

 

extentsreport优化测试报告

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

 

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();