testng优化:失败重跑,extentReport+appium用例失败截图,测试报告发邮件

生成的单html方便jenkins集成发邮件,= = 构建失败发邮件

参考:https://blog.csdn.net/galen2016/article/details/77975965

步骤:

  1.安装Email Extension Plugin插件

  2.系统管理--系统设置

    --设置jenkins Location的邮箱,这里是管理员邮箱,要和发件人的邮箱设置为同一个

 

    --设置email extension plugin

    --设置邮件通知,可以测试一下收发件

  2.进入项目-设置-构建后操作

  

    --高级设置

    --Default Content内容

<!DOCTYPE html>  
<html>  
<head>  
<meta charset="UTF-8">  
<title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>  
</head>  

<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"  
    offset="0">  
    <div>
    <table width="95%" cellpadding="0" cellspacing="0" 
        style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif"> 

        <tr>
            <th align="center" colspan="2"><br />
                <h2>构建信息</h2> 
            </th>
        </tr>
        <tr>  
            <td>  
                <ul>  
                    <li>项目名称 : ${PROJECT_NAME}</li><br />  
                    <li>详细测试报告 : <a href="${PROJECT_URL}测试报告">${PROJECT_URL}测试报告</a></li><br />
                    <li>触发原因: ${CAUSE}</li><br />                    
                    <li>项目  Url : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li><br />
                </ul>  
            </td> 
            <td>${JELLY_SCRIPT,template="html"}<br/> 
        </tr>  

        <tr>  
            <td colspan="2" align="center"><br />
            <h2>测试报告</h2>
            </td>  
        </tr>

        <tr>
            <td colspan="2" align="center">
                <div>${FILE ,path="C:/Users/user/workspace/testngDemo/test-output/emailable-report.html"}</div>
            </td>
        </tr>

    </table> 
    </div>

  </body>  
</html>

  

    
 

失败重跑 testng实现 √

 https://blog.csdn.net/u011541946/article/details/78688302

有两种实现方法:

1.用runtestng直接java执行

2.用testng的监听

Retry设定重跑次数

public class Retry implements IRetryAnalyzer {
	private int retryCount =0;
	private int maxRetryCount =2;
	@Override
	public boolean retry(ITestResult result){
		if(retryCount<maxRetryCount){
			retryCount++;
			return true;
		}
		return false;
	}
}  

重跑的监听器

public class RetryTestListener implements IAnnotationTransformer {
    public void transform(ITestAnnotation annotation, Class testClass,
            Constructor testConstructor, Method testMethod) {
        IRetryAnalyzer retry = annotation.getRetryAnalyzer();
        if (retry == null) {
            annotation.setRetryAnalyzer(Retry.class);
        }
    }
}

设置用例结束的监听器

public class ListenerTest extends TestListenerAdapter{
	  @Override
	  public void onFinish(ITestContext testContext){
		  super.onFinish(testContext);
		  Iterator<ITestResult> listOfFailedTests=testContext.getFailedTests().getAllResults().iterator();
		  while(listOfFailedTests.hasNext()){
			  ITestResult failedTest = listOfFailedTests.next();
			  ITestNGMethod method = failedTest.getMethod();
			  if(testContext.getFailedTests().getResults(method).size()>1){
				  listOfFailedTests.remove();
			  }else{
				  if(testContext.getPassedTests().getResults(method).size()>0){
					  listOfFailedTests.remove();
				  }
			  }
		  }
	  }
}

 

在testng.xml中配置监听器

<listeners >
        <listener class-name="b.testng.reportRelated.ListenerTest"/> 
    	<listener class-name="com.test.RetryTestListener"/>
</listeners>

 

失败用例截图√

截图方法:

public class ScreenScr {
	public static void getScreen(TakesScreenshot driver ,String picName){
		String filePath=System.getProperty("user.dir");
        File pic=driver.getScreenshotAs(OutputType.FILE);
//        String picName=System.currentTimeMillis()+".png";
        try {
            FileUtils.copyFile(pic, new File(filePath+"\pic\"+picName+".png"));
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            Reporter.log("GetScreenshot Successful"+filePath+"\pic\"+picName);
        }
	}
}

失败和截图结合起来,把截图方法放进TestListenerAdapter的继承类里面

public class ListenerTest extends TestListenerAdapter{
	private Logger logger = Logger.getLogger(ListenerTest.class);
	private int m_count = 0;
	String filePath=System.getProperty("user.dir");
          @Override
	  public void onTestFailure(ITestResult tr) {
		  super.onTestFailure(tr);
  		String picName =tr.getStartMillis()+"";
  		ScreenScr.getScreen(PhoneDriver.getPhoneDriver(), picName);
	    log("["+tr.getName()+" Failure ]"+"F");
	    Reporter.log("["+tr.getName()+"失败]");
	  }
	 
	  @Override
	  public void onTestSkipped(ITestResult tr) {
		  super.onTestSkipped(tr);
	  		String picName =tr.getStartMillis()+"";
	  		ScreenScr.getScreen(PhoneDriver.getPhoneDriver(), picName);
	    log("["+tr.getName()+" skipped ]"+"S");
	    Reporter.log("["+tr.getName()+"跳过]");
	  }
}    

  最后一步,把失败截图放进报告,这里我用的extentReporter,继承了IReporter

  这里截取一段用到截图的代码,是extentReporter在报告中,对用例结果的显示的代码,其他项目可以参考。

if (result.getThrowable() != null) {
                	try {
                		String fileName=System.getProperty("user.dir")+"\pic\"+result.getStartMillis()+".png";
						test.addScreenCaptureFromPath(fileName);//本地可看,klov端裂图,klov的bug
						//本地和klov都可看
						test.fail("截图", MediaEntityBuilder.createScreenCaptureFromPath(fileName).build());
					} catch (IOException e) {
						e.printStackTrace();
					}
                    test.log(status, result.getThrowable());
                }else {
                    test.log(status, "Test " + status.toString().toLowerCase() + "ed");
                }

用例执行失败发测试报告邮件

参考:https://www.cnblogs.com/h--d/p/6138900.html

https://www.cnblogs.com/ysocean/p/7666061.html

步骤

  1.写一个发邮件的类Mail,这里把测试报告的html放在附件里面发送了。也可以放在content里面。

package b.testng.reportRelated;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;

public class Email {
	// supply your SMTP host name
	private static String host = "smtp.163.com";
	// supply a static sendTo list
	private static String to = "350xxxxx@qq.com";
	// supply the sender email
	private static String from = "yxxxxx@163.com";

	private static String password = "Yxxxxxx";

	/*
	 * // default cc list 抄送 private static String cc = ""; // default bcc list
	 * 密送 private static String bcc = "";
	 */

	private static String htmlToContents(String htmlPath, String htmlName) {
		String string = "";
		FileReader in;
		try {
			in = new FileReader(htmlPath + htmlName);

			char[] buff = new char[1024 * 10];
			in.read(buff);

			string = new String(buff);
			in.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return string;
	}

	private static void sendEmail(String from, String to, String subject, String content, String htmlPath,
			String htmlName,String attachPath, String attachName) {
		try {
			// 创建参数配置,用于连接邮件服务器
			Properties prop = System.getProperties();
			prop.setProperty("mail.transport.protocol", "smtp");
			prop.setProperty("mail.smtp.host", host);
			prop.setProperty("mail.smtp.auth", "true");
			// 创建会话,和邮件服务器交互
			Session session = Session.getDefaultInstance(prop);
			session.setDebug(true);
			// 创建一封邮件,设置session,发送者,接收者,标题
			MimeMessage message = new MimeMessage(session);
			message.setFrom(new InternetAddress(from));
			message.setSubject(subject);
			List<String> toList = getAddress(to);
			for (String address : toList) {
				message.addRecipient(Message.RecipientType.TO, new InternetAddress(address));
			}
			String contents="";
			
			if (!htmlPath.equals("")) {
				contents =htmlToContents(htmlPath, htmlName);
			}
			contents=content+contents;
			if (!attachPath.equals("")) {
				// 整封邮件的MIME消息体
				MimeMultipart msgMultipart = new MimeMultipart("mixed");
				// ↑有附件,没有附件会报空指针
				message.setContent(msgMultipart);
				// 往MIME消息体中,加入附件
				MimeBodyPart attch = new MimeBodyPart();
				msgMultipart.addBodyPart(attch);
				// 把文件添加到attch中
				// 设置数据源
				DataSource ds = new FileDataSource(new File(attachPath + attachName));
				// 设置数据处理器
				DataHandler dHandler = new DataHandler(ds);
				// 设置第一个附件的数据
				attch.setDataHandler(dHandler);
				// 设置第一个附件的文件名
				attch.setFileName(attachName);
				// 正文
				// 往MIME消息体中,加入文字
				MimeBodyPart text = new MimeBodyPart();
				text.setContent(contents, "text/html;charset=UTF-8");
				message.saveChanges();
			}
			else {
				
				message.setContent(contents, "text/html;charset=UTF-8");
			}
			// 根据session获取邮件传输对象
			Transport transport = session.getTransport();
			transport.connect(from, password);
			transport.sendMessage(message, message.getAllRecipients());
			transport.close();
		} catch (MessagingException e) {
			e.printStackTrace();
		}
	}

	/**
	 * send 2个参数 使用默认邮箱,发送subject和content
	 */
	public static void send(String subject, String contents) {
		sendEmail(from, to, subject, contents,  "", "", "", "");
	}

	/**
	 * send 3个参数 发送 指定邮箱,不发到默认邮箱,subject和content
	 */
	public static void send(String to, String subject, String contents) {
		sendEmail(from, to, subject, contents, "", "", "", "");
	}

	/**
	 * sendAttach 4个参数 使用默认邮箱,发送subject和content,attch
	 */
	public static void sendAttach(String subject, String contents, String attachPath, String attachName) {
		sendEmail(from, to, subject, contents, "", "", attachPath, attachName);
	}

	/**
	 * sendAttach 3个参数 使用默认邮箱,发送subject和content,attch
	 */
	public static void sendAttach(String to, String subject, String contents, String attachPath, String attachName) {
		sendEmail(from, to, subject, contents,  "", "", attachPath, attachName);
	}

	private void sendWithPic(String picPath,String picName,String picURL) throws AddressException, MessagingException{
		Properties prop = System.getProperties();
		prop.setProperty("mail.transport.protocol", "smtp");
		prop.setProperty("mail.smtp.host", host);
		prop.setProperty("mail.smtp.auth", "true");
		// 创建会话,和邮件服务器交互
		Session session = Session.getDefaultInstance(prop);
		session.setDebug(true);
		// 创建一封邮件,设置session,发送者,接收者,标题
		MimeMessage message = new MimeMessage(session);
		message.setFrom(new InternetAddress(from));
		message.setSubject("subject");
		List<String> toList = getAddress(to);
		for (String address : toList) {
			message.addRecipient(Message.RecipientType.TO, new InternetAddress(address));
		}
        
       // 5. 创建图片"节点"
       MimeBodyPart image = new MimeBodyPart();
       // 读取本地文件
       DataHandler dh = new DataHandler(new FileDataSource(picPath+picName));
       // 将图片数据添加到"节点"
       image.setDataHandler(dh);
       // 为"节点"设置一个唯一编号(在文本"节点"将引用该ID)
       image.setContentID(picName);    
        
       // 6. 创建文本"节点"
       MimeBodyPart text = new MimeBodyPart();
       // 这里添加图片的方式是将整个图片包含到邮件内容中, 实际上也可以以 http 链接的形式添加网络图片
       text.setContent("这是一张图片<br/><a href='"+picURL+"'><img src='cid:"+picName+"'/></a>", "text/html;charset=UTF-8");
        
       // 7. (文本+图片)设置 文本 和 图片"节点"的关系(将 文本 和 图片"节点"合成一个混合"节点")
       MimeMultipart mm_text_image = new MimeMultipart();
       mm_text_image.addBodyPart(text);
       mm_text_image.addBodyPart(image);
       mm_text_image.setSubType("related");    // 关联关系
        
       // 8. 将 文本+图片 的混合"节点"封装成一个普通"节点"
       // 最终添加到邮件的 Content 是由多个 BodyPart 组成的 Multipart, 所以我们需要的是 BodyPart,
       // 上面的 mailTestPic 并非 BodyPart, 所有要把 mm_text_image 封装成一个 BodyPart
       MimeBodyPart text_image = new MimeBodyPart();
       text_image.setContent(mm_text_image);
	        //设置邮件的发送时间,默认立即发送
	        message.setSentDate(new Date());
	}

	/**
	 * 发送标题,内容,html
	 * 
	 * @param subject
	 * @param contents
	 * @param htmlPath
	 * @param htmlName
	 */
	public static void sendHtml(String subject, String contents, String htmlPath, String htmlName) {
		sendEmail(from, to, subject, contents, htmlPath, htmlName, "", "");
	}

	/**
	 * 发送标题,html
	 * 
	 * @param subject
	 * @param htmlPath
	 * @param htmlName
	 */
	public static void sendHtml(String subject, String htmlPath, String htmlName) {
		sendEmail(from, to, subject, "", htmlPath, htmlName, "", "");
	}

	private static List<String> getAddress(String address) {
		List<String> addressList = new ArrayList<String>();
		if (address.isEmpty())
			return addressList;

		if (address.indexOf(";") > 0) {
			String[] addresses = address.split(";");

			for (String a : addresses) {
				addressList.add(a);
			}
		} else {
			addressList.add(address);
		}

		return addressList;
	}

}

  

  2.在maven配置中,增加一个插件,该插件可以在测试失败后执行配置的class的main方法

参考https://blog.csdn.net/qq744746842/article/details/51497506

			<plugin>
  				<groupId>org.codehaus.mojo</groupId>
  				  <artifactId>exec-maven-plugin</artifactId>
  				  <version>1.1.1</version>
   				 <executions>
    				    <execution>
     				      <phase>test</phase>
      				      <goals>
        				        <goal>java</goal>
         				  </goals>
        				  <configuration>
         				       <includePluginDependencies>true</includePluginDependencies>
         				       <mainClass>b.testng.reportRelated.Email</mainClass>
            				   <arguments>
              				      <argument>11</argument>
             				      <argument>22</argument>
            				   </arguments>
         				  </configuration>
       				 	</execution>
    				</executions>
  				</plugin>

  

package b.testng.reportRelated;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;

public class Email {
	// supply your SMTP host name
	private static String host = "smtp.163.com";
	// supply a static sendTo list
	private static String to = "350343***@qq.com";
	// supply the sender email
	private static String from = "yindongzi@163.com";
	private static String password = "Yzz1990";

	/*
	 * * // default cc list 抄送 private static String cc = ""; // default bcc
	 * list * 密送 private static String bcc = "";
	 */
	private static String htmlToContents(String htmlPath, String htmlName) {
		String string = "";
		FileReader in;
		try {
			in = new FileReader(htmlPath + htmlName);
			char[] buff = new char[1024 * 10];
			in.read(buff);
			string = new String(buff);
			in.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return string;
	}

private static void sendEmail(String from, String to, String subject, String content, String htmlPath,String htmlName,String attachPath, String attachName) {try {// 创建参数配置,用于连接邮件服务器Properties prop = System.getProperties();prop.setProperty("mail.transport.protocol", "smtp");prop.setProperty("mail.smtp.host", host);prop.setProperty("mail.smtp.auth", "true");// 创建会话,和邮件服务器交互Session session = Session.getDefaultInstance(prop);session.setDebug(true);// 创建一封邮件,设置session,发送者,接收者,标题MimeMessage message = new MimeMessage(session);message.setFrom(new InternetAddress(from));message.setSubject(subject);List<String> toList = getAddress(to);for (String address : toList) {message.addRecipient(Message.RecipientType.TO, new InternetAddress(address));}String contents="";if (!htmlPath.equals("")) {contents =htmlToContents(htmlPath, htmlName);}contents=content+contents;if (!attachPath.equals("")) {// 整封邮件的MIME消息体MimeMultipart msgMultipart = new MimeMultipart("mixed");// ↑有附件,没有附件会报空指针message.setContent(msgMultipart);// 往MIME消息体中,加入附件MimeBodyPart attch = new MimeBodyPart();msgMultipart.addBodyPart(attch);// 把文件添加到attch中// 设置数据源DataSource ds = new FileDataSource(new File(attachPath + attachName));// 设置数据处理器DataHandler dHandler = new DataHandler(ds);// 设置第一个附件的数据attch.setDataHandler(dHandler);// 设置第一个附件的文件名attch.setFileName(attachName);// 正文// 往MIME消息体中,加入文字MimeBodyPart text = new MimeBodyPart();text.setContent(contents, "text/html;charset=UTF-8");message.saveChanges();}else {message.setContent(contents, "text/html;charset=UTF-8");}// 根据session获取邮件传输对象Transport transport = session.getTransport();transport.connect(from, password);transport.sendMessage(message, message.getAllRecipients());transport.close();} catch (MessagingException e) {e.printStackTrace();}}

	/** * send 2个参数 使用默认邮箱,发送subject和content */
	public static void send(String subject, String contents) {
		sendEmail(from, to, subject, contents, "", "", "", "");
	}

	/** * send 3个参数 发送 指定邮箱,不发到默认邮箱,subject和content */
	public static void send(String to, String subject, String contents) {
		sendEmail(from, to, subject, contents, "", "", "", "");
	}

	/** * sendAttach 4个参数 使用默认邮箱,发送subject和content,attch */
	public static void sendAttach(String subject, String contents, String attachPath, String attachName) {
		sendEmail(from, to, subject, contents, "", "", attachPath, attachName);
	}

	/** * sendAttach 3个参数 使用默认邮箱,发送subject和content,attch */
	public static void sendAttach(String to, String subject, String contents, String attachPath, String attachName) {
		sendEmail(from, to, subject, contents, "", "", attachPath, attachName);
	}

private void sendWithPic(String picPath,String picName,String picURL) throws AddressException, MessagingException{Properties prop = System.getProperties();prop.setProperty("mail.transport.protocol", "smtp");prop.setProperty("mail.smtp.host", host);prop.setProperty("mail.smtp.auth", "true");// 创建会话,和邮件服务器交互Session session = Session.getDefaultInstance(prop);session.setDebug(true);// 创建一封邮件,设置session,发送者,接收者,标题MimeMessage message = new MimeMessage(session);message.setFrom(new InternetAddress(from));message.setSubject("subject");List<String> toList = getAddress(to);for (String address : toList) {message.addRecipient(Message.RecipientType.TO, new InternetAddress(address));}               // 5. 创建图片"节点"       MimeBodyPart image = new MimeBodyPart();       // 读取本地文件       DataHandler dh = new DataHandler(new FileDataSource(picPath+picName));       // 将图片数据添加到"节点"       image.setDataHandler(dh);       // 为"节点"设置一个唯一编号(在文本"节点"将引用该ID)       image.setContentID(picName);                   // 6. 创建文本"节点"       MimeBodyPart text = new MimeBodyPart();       // 这里添加图片的方式是将整个图片包含到邮件内容中, 实际上也可以以 http 链接的形式添加网络图片       text.setContent("这是一张图片<br/><a href='"+picURL+"'><img src='cid:"+picName+"'/></a>", "text/html;charset=UTF-8");               // 7. (文本+图片)设置 文本 和 图片"节点"的关系(将 文本 和 图片"节点"合成一个混合"节点")       MimeMultipart mm_text_image = new MimeMultipart();       mm_text_image.addBodyPart(text);       mm_text_image.addBodyPart(image);       mm_text_image.setSubType("related");    // 关联关系               
// 8. 将 文本+图片 的混合"节点"封装成一个普通"节点"       // 最终添加到邮件的 Content 是由多个 BodyPart 组成的 Multipart, 所以我们需要的是 BodyPart,       // 上面的 mailTestPic 并非 BodyPart, 所有要把 mm_text_image 封装成一个 BodyPart       MimeBodyPart text_image = new MimeBodyPart();       text_image.setContent(mm_text_image);        //设置邮件的发送时间,默认立即发送        message.setSentDate(new Date());}

	/**
	 * * 发送标题,内容,html * * @param subject * @param contents * @param htmlPath
	 * * @param htmlName
	 */
	public static void sendHtml(String subject, String contents, String htmlPath, String htmlName) {
		sendEmail(from, to, subject, contents, htmlPath, htmlName, "", "");
	}

	/** * 发送标题,html * * @param subject * @param htmlPath * @param htmlName */
	public static void sendHtml(String subject, String htmlPath, String htmlName) {
		sendEmail(from, to, subject, "", htmlPath, htmlName, "", "");
	}

	private static List<String> getAddress(String address) {
		List<String> addressList = new ArrayList<String>();
		if (address.isEmpty())
			return addressList;
		if (address.indexOf(";") > 0) {
			String[] addresses = address.split(";");
			for (String a : addresses) {
				addressList.add(a);
			}
		} else {
			addressList.add(address);
		}
		return addressList;
	}
}

  

原文地址:https://www.cnblogs.com/zhizhiyin/p/9068631.html