自动化测试时,有时会因为网络不稳定,或者测试环境、第三方环境正在重启而造成用例运行结果不稳定,导致时而能测试通过时而又不通过的测试用例。这些难以重现的环境因素造成的用例失败,经常会耗费排查时间,然而又没有太多改善的空间。针对这种情况,可以基于TestNG的重试器和监听器实现失败结果的重试和监听,一旦监听到失败的测试用例,启动定制的重试方法和处理方法来实现重新运行。
IRetryAnalyzer实现失败重试
TestNG提供了IRetryAnalyzer接口,通过实现这个接口用户可以自定义重试方法,此接口仅定义了一个retry方法
TestNG会自动在添加了RetryAnalyzer的测试方法上监控测试方法的结果,并调用IRetryAnalyzer实现对不同结果的处理。
本文通过pom.xml文件中插件配置重试监听类, Maven工程运行时会自动监听测试类并判断每个测试用例的运行结果,如果测试成功,不做任何动作继续执行下一个测试用例;如果测试失败且执行次数少于最大尝试次数,则进入重试并讲运行次数加一;如果测试失败,并尝试次数大于最大尝试次数,退出当前测试用例,并把测试用例标记为失败。
1、新建OverrideIReTry 类实现 IRetryAnalyzer 接口,这个类主要用于写失败重跑的规则
package com.sc.retry;
import java.util.HashMap;
import java.util.Map;
import org.testng.IRetryAnalyzer;
import org.testng.ITestResult;
import org.testng.Reporter;
public class OverrideIReTry implements IRetryAnalyzer {
// public static Logger logger=Logger.getLogger(OverrideIReTry.class);
//public int initReTryNum=1;
public int maxReTryNum=3;
static Map<String,Integer> countmp = new HashMap<String,Integer>();
@Override
public boolean retry(ITestResult iTestResult) {
Object testcase = iTestResult.getParameters()[0];
int initReTryNum = getTestCaseErrorCount(testcase.toString());
System.out.println(testcase + " ---- " + initReTryNum);
if(initReTryNum<=maxReTryNum){
String message="方法<"+iTestResult.getName()+">执行失败,重试第"+initReTryNum+"次";
System.out.println(message);
Reporter.setCurrentTestResult(iTestResult);
Reporter.log(message);
//initReTryNum++;
return true;
}
return false;
}
private int getTestCaseErrorCount(String key) {
if(countmp.containsKey(key)) {
int count = countmp.get(key);
count++;
countmp.put(key, count);
}else {
countmp.put(key, 1);
}
return countmp.get(key);
}
}
2、 新建OverrideIAnnotationTransformer 类实现 IAnnotationTransformer接口,用于监听事件
package com.sc.retry;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import org.testng.IAnnotationTransformer;
import org.testng.IRetryAnalyzer;
import org.testng.annotations.ITestAnnotation;
public class OverrideIAnnotationTransformer implements IAnnotationTransformer{
@Override
public void transform(ITestAnnotation iTestAnnotation, Class aClass, Constructor constructor, Method method) {
IRetryAnalyzer iRetryAnalyzer= iTestAnnotation.getRetryAnalyzer();
if(iRetryAnalyzer==null){
iTestAnnotation.setRetryAnalyzer(OverrideIReTry.class);
}
}
}
3、邮件工具类EmailUtils和参数处理类EmailParams
mport org.apache.commons.mail.*;
import javax.mail.internet.MimeUtility;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
public class EmailUtils {
public static HtmlEmail emailSet(String title,String emailMsg,String fromEmail,String ps,String[] toEmail) throws EmailException {
HtmlEmail email = new HtmlEmail();
email.setCharset("UTF-8");
email.setHostName(EmailParams.host);
email.setAuthentication(fromEmail,ps);
email.setFrom(fromEmail);//发件人
for(String touser:toEmail){
email.addTo(touser);//收件人
}
email.setSubject(title); //邮件标题
email.setHtmlMsg(emailMsg);//邮件内容
return email;
}
public static HtmlEmail emailSet(String title,String fromEmail,String ps,String[] toEmail) throws EmailException {
HtmlEmail email = new HtmlEmail();
email.setCharset("UTF-8");
email.setHostName(EmailParams.host);
email.setAuthentication(fromEmail,ps);
email.setFrom(fromEmail);//发件人
for(String touser:toEmail){
email.addTo(touser);//收件人
}
email.setSubject(title); //邮件标题
return email;
}
//发送一个简单的邮件,只有内容。
public static void sendEmail(String title,String emailMsg,String fromEmail,String ps,String[] toEmail) throws EmailException {
HtmlEmail email =emailSet(title,emailMsg,fromEmail,ps,toEmail);
email.send();
}
//发送一个多个本地附件的邮件
public static void sendEmailWithAttachments(String title,String emailMsg,String fromEmail,String ps,String[] toEmail,String filepath) throws EmailException {
HtmlEmail email =emailSet(title,emailMsg,fromEmail,ps,toEmail);
String attachmentName="apitest.xlsx,test.xml,0531_7.jpg";
String[] attachs = attachmentName.split(",");
for(String s:attachs){
EmailAttachment emailAttachment = new EmailAttachment();
emailAttachment.setPath(filepath);
emailAttachment.setDisposition(EmailAttachment.ATTACHMENT);
emailAttachment.setDescription("测试结果");
emailAttachment.setName(s);
email.attach(emailAttachment);
}
email.send();
}
//发送一个多个本地附件的邮件
public static void sendEmailWithAttachment(String title,String emailMsg,String fromEmail,String ps,String[] toEmail,String... filepath) throws EmailException {
HtmlEmail email =emailSet(title,emailMsg,fromEmail,ps,toEmail);
for(String s:filepath){
EmailAttachment emailAttachment = new EmailAttachment();
emailAttachment.setPath(s);
emailAttachment.setDisposition(EmailAttachment.ATTACHMENT);
emailAttachment.setDescription("测试结果");
File f = new File(s);
emailAttachment.setName(f.getName());
email.attach(emailAttachment);
}
email.send();
}
public static void sendEmailsWithAttachments(String title, String context, String... filepath) throws EmailException, UnsupportedEncodingException {
String hostname = EmailParams.host;
String password = EmailParams.password;
String username = EmailParams.username;
String[] toList =EmailParams.tousers;
// Create the email message
HtmlEmail email = new HtmlEmail();
email.setHostName(hostname); // 邮件服务器域名
//mail.setSmtpPort(smtpPort); // 邮件服务器smtp协议端口
email.setAuthentication(username, password); // 邮箱账户
email.setCharset("UTF-8"); // 邮件的字符集
//mail.setSSLOnConnect(true); // 是否启用SSL
//mail.setSslSmtpPort(sslSmtpPort); // 若启用,设置smtp协议的SSL端口