市面上最受欢迎的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> 邮件报告效果:
5> log4j 的log明细:
6> extentReports框架生成的报告明细:
五、框架jar包:
PS: 更多原创技术好文和资料,请关注下方公众号:“测试开发栈”公众号是由具有多年测试、开发经验的老兵们共同管理和运营,旨在分享原创测试、开发相关技术,包括但不限于:测试方向:Web自动化测试、移动端自动化测试、Web服务端测试、接口测试等;开发方向:Java开发、Android开发、前端开发等;期望我们的经验和技术分享能让你每天都成长和进步,早日成为技术大牛~欢迎大家分享和转发我们的文章(分享转发请保留文章出处),以便让更多的朋友关注我们,同时也欢迎加入我们的QQ群交流和提问:427020613