市面上最受欢迎的 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("automation@163.com") //设置发送邮箱的账号
.setSendPassword("123456) //设置发送邮箱的账号密码
.setReceivers("alany@xx.com;alany2@xx.com") //邮件接收者账号,多个账号用分号隔开
.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("automation@163.com")
.setSendPassword("123456")
.setReceivers("alany@XX.com")
.setSubject("Test Log4Reports")
.build();
System.out.println("init log config finished.");
}
}
4> 邮件报告效果:
5> log4j 的 log 明细:
6> extentReports 框架生成的报告明细:
五、框架 jar 包:
原文链接:http://www.jianshu.com/p/2c3fd46e2357