这个是我后来写的一本书,http://www.ituring.com.cn/minibook/10775。这个是我后来找到的自动化完美解决方案。
对于一个自动化框架来说,它的第二个实现重点是测试报告的生成。可以想象如果没测试报告,那我还跑自动化干什么呢?如果测试报告展示的测试结果不清晰不友好,那你希望谁去分析你的测试报告呢?所以对于一个自动化框架来说,测试报告功能也是它其中的一个重点。
测试报告包含的信息要有,1,自动化运行的每个步骤,自动化运行中失败的原因记录,自动化测试结果成功或失败的提示文件以及还有包含能分门别类存放测试报告的文件夹。
首先,常规运行信息的记录我们选用log4j,对log4j进行定制以实现我们的功能。
那么在
定义一个方法初始化自定义log
public static void initializeLogger(String logname, Level logLevel, Logger l){
PatternLayout layout = new PatternLayout();
//自定义定义报告输不输出日期时间等
layout.setConversionPattern( "%p %d{ABSOLUTE} %c - %m%n" );
FileAppender appender = null;
try {
//logname为我们想存放日志的路径。
appender = new FileAppender(layout, logname, false);
} catch(Exception e) {
Logger.getLogger("framework.LogManager").error("Log.initializeLogger - Could not initialize logger for " + logname);
}
l.addAppender(appender);
l.setLevel(logLevel);
}
因为要传入的log level在很多时候可以采取默认值。所以我们可以重载此方法。
private static Level LOG_LEVEL = Level.INFO;
public static void initializeLogger(String logname, Logger l){
initializeLogger(logname, LOG_LEVEL, l);
}
如何使用它呢,看下面
ManageLog Log=new Managelog();
Log.initializeLogger(scriptLogDir + "scriptLog.txt", this.scriptLogger);
这个scriptLogDir 是你在运行时传入指定的路径名,
//System.getenv("ROOT")获得本机名称。
this.scriptLogDir = System.getenv("ROOT") + "var" + File.separator + "output" + File.separato+OUTPUT_DIR_DYNAMIC_PART + File.separator+ + "logs/";
private static final String OUTPUT_DIR_DYNAMIC_PART = new SimpleDateFormat(
"yyyyMMddHHmmssSSS").format(new Date());
}
this.scriptLogger是你得log日志文件名。它是如何使用的看下面
this.scriptLogger = Logger.getLogger(String.valueOf(Testcase.getTestcaseID()));
我们看里面getTestcaseID()方法
public long getTestcaseID(){
Date now = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmssSS");
Random rdm = new Random();
int rnumber = rdm.nextInt(999999);
//用时间加随机字符做文件名
testcaseID = Long.valueOf(formatter.format(now))+rnumber;
return testcaseID;
}
好的,下面说下运行时如果出错的时候测试日志怎么实现,首先我们要自定义 Exception
我们自定义的Exception要实现那些方法呢?我们先定义一个父类
public abstract class MangerException extends Exception {
public static final long serialVersionUID = 1L;
/** Creates a data structure to store necessary information about exception */
protected HashMap<String,String> dataInfo = null;
/** reference to BertModuleManager */
protected BertModuleManager bmmObjRef = null;
/** holds failure type string */
protected String failureType = BertTestCase.STATUS.FAILED;
/** holds error string */
private String message= null;
/** holds name of exception */
private String exceptionName = null;
/** Creates a new instance of bertException
* @param msg - Error message
*/
public MangerException(String msg, String eName) {
this.message = msg;
this.exceptionName = eName;
}
/**
* This method return the error message associated with the exception object
* @return - error message
*/
public String getMessage(){
return this.message;
}
/**
* This method sets an error message
* @param msg - error message
*/
public void setMessage(String msg){
this.message = msg;
}
/** get the failure type PROBLEM / ERROR */
public String getFailureType() {
return this.failureType;
}
/**
* this method is an interface which should be called from business modules to
* analyze the root cause of failure
* @param objRef
*/
public void processExcpetion(ReadXMLManager objRef){
try {
this.bmmObjRef = objRef;
this.collectInformation();
this.analyze();
this.store();
}
catch(Exception e){
objRef.getLogger().fatal(this.getClass().getName() + " :: Could not analyze root cause of problem");
}
}
/**
* get analyzed data - dataInfo
* @return
*/
public HashMap<String,String> getDataInfo(){
return this.dataInfo;
}
public String getExceptionName(){
return this.exceptionName;
}
/** collection information associated with failure for reporting */
public abstract void collectInformation();
/** analyze various aspect of failure */
public abstract void analyze();
/** store information to BertTestCase object */
public abstract void store();
}
在定义各个实现的子类,下面仅举出两个例子。
1 ,public class HtmlElementException extends MangerException{
public static final long serialVersionUID = 1L;
// an object of GUIEvent class.
private GUIEvent GUIE = null;
// logger object
private Logger loggerObj = Logger.getLogger(Thread.currentThread().getName());
// object to get access to external library.
private JstLibWebUtil util = null;
/** Creates a new instance of XMLValidationErrorException
* @param msg - Error message
*/
public HtmlElementException(String msg) {
super(msg, "HtmlElementNotFoundException");
}
/** empty could be used in future */
public void collectInformation(){}
/** collecting information from the failed web page. */
public void analyze(){
// initialize global HashMap object to collect data into report.
this.dataInfo = new HashMap<String,String>();
this.GUIE = this.bmmObjRef.getGUIEventObj();
this.util = new JstLibWebUtil(this.GUIE);
try {
dataInfo.put ( "DomainName : ", this.util.getDomainName());
dataInfo.put ( "WebServerName : ", this.util.getWebServerName() + " - date: " + DateUtil.getFormatDateTime("yyyy-MM-dd HH:mm:ss"));
}catch(Exception e){ this.loggerObj.debug(this.getClass().getName() + " :: " + e.getMessage());}
}
/** empty could be used in future */
public void store(){}
}
2,public class DatabaseTimeoutException extends MangerException {
public static final long serialVersionUID = 1L;
/**
* Creates a new instance of DatabaseTimeoutException
* @param msg - Error message
*/
public DatabaseTimeoutException(String msg) {
super(msg, "Database-Timeout-Exception");
}
/** empty could be used in future */
public void collectInformation(){}
/** empty could be used in future */
public void analyze(){}
/** empty could be used in future */
public void store(){}
}
使用的时候这样使用就行了
if (!comment.isEmpty()) {
throw new HtmlElementException(this.getClass().getName()+" :: Failed in Check Order Comment Should be Empty");
}
下面说下当很多脚本一起运行的时候测试报告是如何显示。
public void startReport(String reportDir,String reportFile,String sts){
File f = new File(reportDir + reportFile);
try {
f.createNewFile();
out = new PrintWriter(new FileWriter(f), true);
// html head
appendFile(BertBase.getBertConfRoot()+"report.head");
// 记录下脚本运行时失败成功阻塞的数量
out.println( "=== " + this.area + " Summary ===<br/><br/>");
out.println("TEST CASES PASSED --> " + this.result.passed + "<br/>");
out.println("TEST CASES BLOCKED --> " + this.result.avoided + "<br/>");
out.println("TEST CASES FAILED --> " + this.result.failed + "<br/>");
out.println("TEST CASES TIMED OUT --> " + this.result.skipped + "<br/>");
out.println("TOTAL EXECUTED --> " + this.result.totalExecuted + "<br/>");
out.println("TOTAL --> " + this.result.total + "<br/>");
out.println("<b><i>Execution time</i></b>: "+fmt.format(start) + "~" + fmt.format(end)
+ " ( " + this.getExecutionDuration(this.start, this.end) + " )<br/>");
catch (Exception ex) {
this.Logger.error("Error when create area report (" + f.toString()+")" + ex );
ex.printStackTrace();
} finally{
if(out != null){
out.close();
}
}