Java&Selenium&TestNG&ZTestReport 自动化测试并生成HTML自动化测试报告

一、摘要
本篇博文将介绍如何借助ZTestReport和HTML模版,生成HTML测试报告的ZTestReport 源码Clone地址为 https://github.com/zhangfei19841004/ztest,其中ZTestReport.java

和其template是我们需要的关键。

二、ZTestReport.java
根据我的需要,在源码基础上进行了稍微修改,其中几个注释的地方需要注意,将其集成进自己的自动化框架时需要做相应的修改

package util;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.testng.*;
import org.testng.xml.XmlSuite;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;


public class TestReport implements IReporter {
    private long currentTime = System.currentTimeMillis();
    private SimpleDateFormat formatter = new SimpleDateFormat ("yyyy年-MM月-dd日-HH时mm分ss秒");
    private Date date = new Date(currentTime);
    private String reportdate = formatter.format(date);
    // 定义生成测试报告的路径和文件名,为兼容Windows和Linux此处使用File.separator代替分隔符
    private String path = System.getProperty("user.dir")+File.separator+reportdate+".html";
    // 定义html样式模板所在路径
    private String templatePath = System.getProperty("user.dir")+File.separator+"template";
    
    private int testsPass = 0;

    private int testsFail = 0;

    private int testsSkip = 0;
    
    private String beginTime;
    
    private long totalTime;
    
    private String name = "PaaS平台自动化测试";
    /**
    public TestReport(){
        long currentTime = System.currentTimeMillis();
        SimpleDateFormat formatter = new SimpleDateFormat ("yyyy年-MM月-dd日-HH时mm分ss秒");
        Date date = new Date(currentTime);
        name = formatter.format(date);
    }
    
    public TestReport(String name){
        this.name = name;
        if(this.name==null){
            long currentTime = System.currentTimeMillis();
            SimpleDateFormat formatter = new SimpleDateFormat ("yyyy年-MM月-dd日-HH时mm分ss秒");
            Date date = new Date(currentTime);
            this.name = formatter.format(date);
        }
    }
    */
    @Override
    public void generateReport(List xmlSuites, List suites, String outputDirectory) {
        List list = new ArrayList();
        for (ISuite suite : suites) {
            Map suiteResults = suite.getResults();
            for (ISuiteResult suiteResult : suiteResults.values()) {
                ITestContext testContext = suiteResult.getTestContext();
                IResultMap passedTests = testContext.getPassedTests();
                testsPass = testsPass + passedTests.size();
                IResultMap failedTests = testContext.getFailedTests();
                testsFail = testsFail + failedTests.size();
                IResultMap skippedTests = testContext.getSkippedTests();
                testsSkip = testsSkip + skippedTests.size();
                IResultMap failedConfig = testContext.getFailedConfigurations();
                list.addAll(this.listTestResult(passedTests));
                list.addAll(this.listTestResult(failedTests));
                list.addAll(this.listTestResult(skippedTests));
                list.addAll(this.listTestResult(failedConfig));
            }
        }
        this.sort(list);
        this.outputResult(list);
    }

    private ArrayList listTestResult(IResultMap resultMap) {
        Set results = resultMap.getAllResults();
        return new ArrayList(results);
    }

    private void sort(List list) {
        Collections.sort(list, new Comparator() {
            @Override
            public int compare(ITestResult r1, ITestResult r2) {
                if (r1.getStartMillis() > r2.getStartMillis()) {
                    return 1;
                } else {
                    return -1;
                }
            }
        });
    }

    private void outputResult(List list) {
        try {
            List listInfo = new ArrayList();
            int index = 0;
            for (ITestResult result : list) {
                String tn = result.getTestContext().getCurrentXmlTest().getParameter("testCase");
                if(index==0){
                    SimpleDateFormat formatter = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss");
                    beginTime = formatter.format(new Date(result.getStartMillis()));
                    index++;
                }
                long spendTime = result.getEndMillis() - result.getStartMillis();
                totalTime += spendTime;
                String status = this.getStatus(result.getStatus());
                List log = Reporter.getOutput(result);
                for (int i = 0; i < log.size(); i++) {
                    log.set(i, log.get(i).replaceAll("\"", "\\\\\""));
                }
                Throwable throwable = result.getThrowable();
                if(throwable!=null){
                    log.add(throwable.toString().replaceAll("\"", "\\\\\""));
                    StackTraceElement[] st = throwable.getStackTrace();
                    for (StackTraceElement stackTraceElement : st) {
                        log.add(("    " + stackTraceElement).replaceAll("\"", "\\\\\""));
                    }
                }
                ReportInfo info = new ReportInfo();
                info.setName(tn);
                info.setSpendTime(spendTime+"ms");
                info.setStatus(status);
                info.setClassName(result.getInstanceName());
                info.setMethodName(result.getName());
                info.setDescription(result.getMethod().getDescription());
                info.setLog(log);
                listInfo.add(info);
            }
            Map result = new HashMap();
            result.put("testName", name);
            result.put("testPass", testsPass);
            result.put("testFail", testsFail);
            result.put("testSkip", testsSkip);
            result.put("testAll", testsPass+testsFail+testsSkip);
            result.put("beginTime", beginTime);
            result.put("totalTime", totalTime+"ms");
            result.put("testResult", listInfo);
            Gson gson = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create();
            String template = this.read(templatePath);
            BufferedWriter output = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(new File(path)),"UTF-8"));
            template = template.replaceFirst("\\$\\{resultData\\}", Matcher.quoteReplacement(gson.toJson(result)));
            output.write(template);
            output.flush();
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private String getStatus(int status) {
        String statusString = null;
        switch (status) {
        case 1:
            statusString = "成功";
            break;
        case 2:
            statusString = "失败";
            break;
        case 3:
            statusString = "跳过";
            break;
        default:
            break;
        }
        return statusString;
    }
    
    public static class ReportInfo {
        
        private String name;
        
        private String className;
    
        private String methodName;
        
        private String description;
        
        private String spendTime;
                
        private String status;
        
        private List log;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getClassName() {
            return className;
        }

        public void setClassName(String className) {
            this.className = className;
        }

        public String getMethodName() {
            return methodName;
        }

        public void setMethodName(String methodName) {
            this.methodName = methodName;
        }

        public String getSpendTime() {
            return spendTime;
        }

        public void setSpendTime(String spendTime) {
            this.spendTime = spendTime;
        }

        public String getStatus() {
            return status;
        }

        public void setStatus(String status) {
            this.status = status;
        }

        public List getLog() {
            return log;
        }

        public void setLog(List log) {
            this.log = log;
        }

        public String getDescription() {
            return description;
        }

        public void setDescription(String description) {
            this.description = description;
        }
        
    }
    
    private String read(String path) {
        File file = new File(path);
        InputStream is = null;
        StringBuffer sb = new StringBuffer();
        try {
            is = new FileInputStream(file);
            int index = 0;
            byte[] b = new byte[1024];
            while ((index = is.read(b)) != -1) {
                sb.append(new String(b, 0, index));
            }
            return sb.toString();
        } catch (FileNotFoundException e) {

            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}

三、template

template文件是和ZTestReport.java一起使用的,他可以将TestNG的测试结果按照template的样式转换成HTML格式的报告

四 创建监听类

package com.test.listener;

import com.hand.utils.ScreenShot;
import com.test.BaseTest;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.WebDriver;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter;
import org.testng.annotations.Listeners;

@Slf4j
public class TestLogListener extends TestListenerAdapter {
    @Override
    public void onStart(ITestContext iTestContext) {
        super.onStart( iTestContext );
        log.info( String.format( "====================%s测试开始====================", iTestContext.getName() ) );
    }

    @Override
    public void onTestStart(ITestResult iTestResult) {
        super.onTestStart( iTestResult );
        log.info( String.format( "========%s.%s测试开始========", iTestResult.getInstanceName(), iTestResult.getName()) );
    }

    @Override
    public void onTestSuccess(ITestResult iTestResult) {
        super.onTestSuccess( iTestResult );
        log.info( String.format( "========%s.%s测试通过========", iTestResult.getInstanceName(), iTestResult.getName()) );
    }

    @Override
    public void onTestFailure(ITestResult iTestResult) {
        WebDriver driver = BaseTest.driverBase.getDriver();
        System.out.print( "report_driver_fail:" + driver );
        super.onTestFailure( iTestResult );
        log.error( String.format( "========%s.%s测试失败,失败原因如下:\n%s========", iTestResult.getInstanceName(), iTestResult.getName(), iTestResult.getThrowable() ));
        // 失败截图
        ScreenShot.takeScreenShot( driver,iTestResult);
    }

    @Override
    public void onTestSkipped(ITestResult iTestResult) {
        super.onTestSkipped( iTestResult );
        log.info( String.format( "========%s.%s跳过测试========", iTestResult.getInstanceName(), iTestResult.getName()) );
    }

    @Override
    public void onFinish(ITestContext iTestContext) {
        super.onFinish( iTestContext );
        log.info( String.format( "====================%s测试结束====================", iTestContext.getName() ) );
    }
}

五设置监听

两种方法:1在代码中设置
//固定写法     你的监听类(继承TestListenerAdapter的类)                
@Listeners({ com.example.MyListener.class, com.example.MyMethodInterceptor.class })
public class MyTest {//测试类
  // ...
}
二:在xml文件中声名

        
        
    

六拓展截图

package com.hand.utils;

import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.testng.ITestResult;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ScreenShot{
    private static String screenShotDirPath = System.getProperty("user.dir") + File.separator +"target" + File.separator + "test-output" + File.separator + "errorScreenShot";

    public static void takeScreenShot(WebDriver driver,ITestResult iTestResult) {
        Object currentClass = iTestResult.getInstance();// 获取当前 Object 类型的测试类
        //获取包名
        String packageName = currentClass.getClass().getPackage().getName();
        System.out.println("packageName : " + packageName);
 /*       //根据获得的类名,去掉包名
        String currentClassName = currentClass.toString().replaceAll(packageName,"");
        System.out.println("currentClassName : " + currentClassName);*/
        String currentClassName = currentClass.toString();

        //正则匹配
        Pattern pattern = Pattern.compile(packageName+".(.*?)@");//此处为正则表达式
        Matcher matcher = pattern.matcher(currentClassName);//去匹配正则表达式
        while (matcher.find()) {
            currentClassName = matcher.group(1);
            System.out.println("currentClassName:" + currentClassName);
        }
    //  System.out.println("出错的类为:" + currentClassStr);

        File screenShotDir = new File(screenShotDirPath);
        if (!screenShotDir.exists() && !screenShotDir.isDirectory()) {
            screenShotDir.mkdirs();
        }
        //SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年-MM月-dd日-HH时-mm分-ss秒SSS");
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH点mm分ss秒");
        String time = simpleDateFormat.format(new Date());
        try {
            File source_file = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);                              // 屏幕截图
            //System.out.println("出错的截图命名为:" + currentClass.toString() + ".png");
            FileUtils.copyFile(source_file, new File(screenShotDirPath + File.separator + currentClassName + time + ".png"));  // 另存截图
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

你可能感兴趣的:(Java&Selenium&TestNG&ZTestReport 自动化测试并生成HTML自动化测试报告)