自定义自动化测试日志框架-Log4Reports

市面上最受欢迎的Java日志组件可能要属log4j了,log4j灵活丰富的配置可以帮助开发人员全方位地掌控日志信息。然而对于软件自动化测试来说,无论是log4j,还是Junit 、testNG等测试框架下自动生成的日志和报告,对结果统计和数据展现的表现力就没那么优秀了,但是log4j它详尽的log信息又是我们需要的,鉴于此我在这里将log4j和拥有图表统计的extentReports日志框架结合在一起,从而满足对于不同的需求,选择不同的日志框架。
对于extentReports框架做一个简单的介绍,它是国外大牛Anshoo Arora写的一个开源报告框架,项目开源代码地址:https://github.com/anshooarora/extentreports ,对于extentReports的使用大家可以参考官网(http://extentreports.com )的API和例子去实现(我最开始使用的时候全都是免费的,现在已出付费版了,真羡慕国外随便搞个工具(关键是人家还开源)都可以赚钱,在国内分分钟给你山寨出来一大堆),闲话不多说,下面正式进入框架的功能和实现步骤:

一、框架说明
Log4Reports框架其实包含了:log4j + extentReports + TestNG,框架封装了log4j和extentReports两套日志框架功能,并基于TestNG创建了BaseCase类,用于组织和管理测试用例。Log4Reports框架已上传到github(**https://github.com/AlanYangs/Log4Reports **),欢迎大家使用~

二、创建log配置类LogConfig
LogConfig类主要是用于初始化log文件路径及配置一些log的参数,采用Builder模式实例化对象(主要作用为给变量赋值)

public class LogConfig{
        /**日志类型 ,默认为extentreports, 0 = extentreports, 1 = log4j **/
    public static int logType = 0;
    /**失败重跑次数,默认0,失败不重跑**/
    public static int retryTimes = 0; 
        /**日志存放路径,最好是一个共享路径**/
    public static String sharedFolder = System.getProperty("user.dir");
    /**如需发送邮件,请配置SMTP host,比如163邮箱:smtp.163.com**/
    public static String smtpHost;
        /**发送邮箱的账号**/
    public static String sender;
    /**发送邮箱的账号密码**/
    public static String sendPassword;
    /**邮件接收者账号**/
    public static String receivers;
        /**邮件主题,默认:"Test Report Generated By Log4Reports"**/
    public static String subject;

    private String sharedPath;
    private String log4jFolder;
    private String log4jPath;
    private String extentFolder;
    private String extentLogPath;
    private String snapshotFolder;
    
    public LogConfig(Builder builder) {
        LogConfig.logType = builder.logType;
        LogConfig.retryTimes = builder.retryTimes;
        LogConfig.sharedFolder = builder.sharedFolder;
        LogConfig.smtpHost = builder.smtpHost;
        LogConfig.sender = builder.sender;
        LogConfig.sendPassword = builder.sendPassword;
        LogConfig.receivers = builder.receivers;
        LogConfig.subject = builder.subject;
                initLogPath(); //初始化日志文件夹
    }

    public static class Builder {
        private int logType = 0;
        private int retryTimes = 0;
        private String sharedFolder = "";
        
        private String smtpHost;
        private String sender;
        private String sendPassword;
        
        private String receivers;
        private String subject = "Test Report Generated By Log4Reports";
        
        public Builder(String sharedFolder){
            this.sharedFolder = sharedFolder;
        }
        
        public Builder setLogType(int logType) {
            this.logType = logType;
            return this;
        }

        public Builder setRetryTimes(int retryTimes) {
            this.retryTimes = retryTimes;
            return this;
        }
        
        public Builder setSmtpHost(String smtpHost) {
            this.smtpHost = smtpHost;
            return this;
        }
        
        public Builder setSender(String sender) {
            this.sender = sender;
            return this;
        }
        

        public Builder setSendPassword(String sendPassword) {
            this.sendPassword = sendPassword;
            return this;
        }
        
        public Builder setReceivers(String receivers) {
            this.receivers = receivers;
            return this;
        }
        
        public Builder setSubject(String subject) {
            this.subject = subject;
            return this;
        }
        
                public LogConfig build(){
                  return new LogConfig(this);
                }
    }
        private void initLogPath(){
        sharedPath =  CommonUtil.getFileName(LogConfig.sharedFolder);
        log4jFolder = sharedPath + "\\logs\\";
        log4jPath = sharedPath + "\\logs\\output.log";
        extentFolder = sharedPath + "\\reports\\";
        extentLogPath = sharedPath + "\\reports\\reports.html";
        snapshotFolder = sharedPath + "\\reports\\snapshot\\";
        
        File file;
        if(LogConfig.logType == 0){ 
            file = new File(extentFolder);
            if(!file.exists()) file.mkdir();
        }else{
            file = new File(log4jFolder);
            if(!file.exists())file.mkdir();
        }
        
        if(LogConfig.logType == 0 && new File(extentLogPath).exists() || 
                LogConfig.logType == 1 && new File(log4jPath).exists()){
            if(deleteDir(file)) file.mkdir();
            if(file.exists() && file.list().length == 0){
                System.out.println("初始化日志文件夹【成功】");
            }else{
                System.out.println("初始化日志文件夹【失败】");
            }
        }
    }

    /**
     * @return the log4jPath
     */
    public String getLog4jPath() {
        return log4jPath;
    }

    /**
     * @return the extentLogPath
     */
    public String getExtentLogPath() {
        return extentLogPath;
    }

    /**
     * @return the snapshotFolder
     */
    public String getSnapshotFolder() {
        return snapshotFolder;
    }
}

三、创建log操作类LogUtil
LogUtil是整个框架的核心之一,主要封装了log4j 和 extentReports框架的对象及操作方法,实现步骤如下:
1> LogUtil的构造方法,基于不同log类型选择log方式

public class LogUtil {
    private Logger logger;
    private ExtentReports report;
    private ExtentTest testLog;
    
    private LogConfig logConfig;

        public LogUtil(LogConfig config, Object obj){
        this.logConfig = config;
        if(LogConfig.logType == 0){
            File configFile = new File(System.getProperty("user.dir") + "\\configs\\extent-config.xml");
            if(configFile.exists()) {
                report = new ExtentReports(config.getExtentLogPath(),false);
                report.loadConfig(configFile);      
            }       
            testLog = report.startTest(String.valueOf(obj));
        }else{
            logger = Logger.getLogger(String.valueOf(obj));
            Layout layout = new PatternLayout("%d{yyyy-MM-dd HH:mm:ss} [%p] %c:%L : %m%n");  
            try {
                Appender appender = new FileAppender(layout, config.getLog4jPath());
                logger.addAppender(appender);
            } catch (IOException e) {
                e.printStackTrace();
            } 
        }
    }
  ……

2> 实现具体的log方法

public class LogUtil {
        ……
    public int failCount = 0;
    public int errorCount = 0;
    public int warnCount = 0;
    public int skipCount = 0;
        ……
    //info
    public void info(String info){
        if(LogConfig.logType == 0){
            testLog.log(LogStatus.INFO, info);
            System.out.println(info);
        }else{
            logger.info(info);
        }
    }
    
    //warning
    public void warn(String warning){
        if(LogConfig.logType == 0){
            testLog.log(LogStatus.WARNING, warning);
            System.out.println(warning);
        }else{
            logger.warn(warning);
        }
        warnCount++;
    }
    
    //error
    public void error(String error){
        if(LogConfig.logType == 0){
            testLog.log(LogStatus.ERROR, error + snapshot());
            System.out.println(error);
        }else{
            logger.error(error);
        }
        errorCount++;
    }
    
    //skip
    public void skip(String skip){
        if(LogConfig.logType == 0){
            testLog.log(LogStatus.SKIP, skip);
            System.out.println(skip);
        }
        skipCount++;
    }
    
    //unknow
    public void unknow(String unknow){
        if(LogConfig.logType == 0){
            testLog.log(LogStatus.UNKNOWN, unknow);
            System.out.println(unknow);
        }
    }
    
    //fatal
    public void fatal(String fatal){
        if(LogConfig.logType == 0){
            testLog.log(LogStatus.FATAL, fatal + snapshot());
            System.out.println(fatal);
        }else{
            logger.fatal(fatal);
        }
        failCount++;
    }
    
    //fail
    public void fail(Throwable throwable){
        if(LogConfig.logType == 0){
            testLog.log(LogStatus.FAIL, snapshot() + throwable);
            System.out.println(throwable);
        }else{
            logger.error(throwable);
        }
        failCount++;
    }
    
    //fail
    public void fail(String fail){
        if(LogConfig.logType == 0){
            testLog.log(LogStatus.FAIL, fail + snapshot());
            System.out.println(fail);
        }else{
            logger.error(fail);
        }
        failCount++;
    }
    
    //pass
    public void pass(String pass){
        if(LogConfig.logType == 0){
            testLog.log(LogStatus.PASS, pass);
            System.out.println(pass);
        }else{
            logger.info(pass);
        }
    }
    ……
}

四、使用Log4Reports框架
1> 创建测试类继承Log4Reports框架的BaseCase类,并实现initConfig()方法:

public class TestCase1 extends **BaseCase** {
        ……
        //实现BaseCase的initConfig()方法
        @Override
    public void initConfig() {
        // TODO Auto-generated method stub
        logConfig = new LogConfig.Builder("\\\\172.0.0.1\\SharedFolder") //设置共享目录
        .setLogType(0)      //设置日志类型
        .setRetryTimes(1) //设置失败重跑次数
        .setSmtpHost("smtp.163.com") //设置发送邮箱的smtp host
        .setSender("[email protected]") //设置发送邮箱的账号
        .setSendPassword("123456) //设置发送邮箱的账号密码
        .setReceivers("[email protected];[email protected]") //邮件接收者账号,多个账号用分号隔开
        .setSubject("Test Log4Reports") //邮件主题
        .build();
        System.out.println("init log config finished.");
    }
}

2> 需要使用TestNG的@BeforeClass(BaseCase中使用的注解包括:@BeforeSuite、@AfterSuite、@BeforeClass、@AfterClass、@BeforeMethod、@AfterMethod 这6个)等注解时,需要先调用父类对应方法:

        @BeforeClass
    public void beforeClass() {
        super.beforeClass();
        /** 下面实现你自己的逻辑 **/
    }
        @AfterClass
    public void afterClass(){
              super.afterClass();
          /** 下面实现你自己的逻辑 **/
        }
    @AfterMethod
    public void afterMethod(ITestResult result) {
        super.afterMethod(result);
        /** 下面实现你自己的逻辑 **/
    }
        
        /** 不是上述的6个注解,不用调用父类的方法 **/

3>使用@Test注解编写测试方法:

public class TestCase1 extends BaseCase{
    private int flag = 0;
    
    @BeforeClass
    public void beforeClass() {
        super.beforeClass();
        flag = 1;
    }
    
    @AfterMethod
    public void afterMethod(ITestResult result) {
        super.afterMethod(result);
        flag = flag >1 ? 1 : flag;
    }
    
    @Test
    public void test(){
        if(assertEquals(flag, 1, true)){
            flag ++;
        }
        Log.info("this is info log");
        Log.pass("this is pass log");   
    }
    
    @Test
    public void test2(){
        if(assertEquals(flag, 2, true)){
            flag --;
        }
        Log.info("this is info log----A");
        Log.error("this is error log---B");
        Log.warn("this is warning log----C");
        Log.pass("this is pass log----D");
        Log.fail("this is fail log----E");
    }

    @Override
    public void initConfig() {
        // TODO Auto-generated method stub
        logConfig = new LogConfig.Builder("\\\\172.0.0.1\\SharedFolder")
        .setLogType(0)
        .setRetryTimes(1)
        .setSmtpHost("smtp.163.com")
        .setSender("[email protected]")
        .setSendPassword("123456")
        .setReceivers("[email protected]")
        .setSubject("Test Log4Reports")
        .build();
        System.out.println("init log config finished.");
    }
}

4> 邮件报告效果:


自定义自动化测试日志框架-Log4Reports_第1张图片
Paste_Image.png

5> log4j 的log明细:


自定义自动化测试日志框架-Log4Reports_第2张图片
Paste_Image.png

6> extentReports框架生成的报告明细:


自定义自动化测试日志框架-Log4Reports_第3张图片
Paste_Image.png

五、框架jar包:

Log4Reports_1.0.0.jar

PS: 更多原创技术好文和资料,请关注下方公众号:“测试开发栈”公众号是由具有多年测试、开发经验的老兵们共同管理和运营,旨在分享原创测试、开发相关技术,包括但不限于:测试方向:Web自动化测试、移动端自动化测试、Web服务端测试、接口测试等;开发方向:Java开发、Android开发、前端开发等;期望我们的经验和技术分享能让你每天都成长和进步,早日成为技术大牛~欢迎大家分享和转发我们的文章(分享转发请保留文章出处),以便让更多的朋友关注我们,同时也欢迎加入我们的QQ群交流和提问:427020613


自定义自动化测试日志框架-Log4Reports_第4张图片

你可能感兴趣的:(自定义自动化测试日志框架-Log4Reports)