引言:
有时工作中有事临时走开,如果执行case过程中没有出错,不出意外是不会看日志了,但是如果忘了看执行结果怎么办??总不能重新运行一次,所以今天讲邮件发送,叮~一声,提醒我们看邮箱。
注:依赖环境Allure、JsonPath、testNG;
1.引入pom依赖:
<!-- https://mvnrepository.com/artifact/javax.mail/mail -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
2.封装一个发送邮件的util,代码如下:
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import org.apache.log4j.Logger;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.io.*;
import java.util.*;
/**
* @author Knife
* @description 发送自动化测试报告
* @createTime 2020-05-13 21:53
*/
public class SendEmail extends Rest_Perfect {
private static Logger logger = Logger.getLogger(SendEmail.class);
private static SendEmail sendEmail;
static {
}
/**
* 获取sendEmail对象
*
* @return
*/
public static SendEmail getInstance() {
if (Objects.isNull(sendEmail)) {
sendEmail = new SendEmail();
}
return sendEmail;
}
/**
* 发送邮件
*
* @param title 邮件标题
* @param filePath allure-report中suite.json文件路径
* @param addresseeEmail 收件邮箱
*/
public static void send(String title, String filePath, String addresseeEmail) {
//根据运行测试类,和main入口判断
String p = SendEmail.class.getResource("/").getPath();
String[] split = p.split("/");
for (String s : split) {
if ("test-classes".equals(s)) {
filePath = p.substring(0, p.indexOf("/test-classes")) + filePath;
}
if ("classes".equals(s)) {
filePath = p.substring(0, p.indexOf("/classes")) + filePath;
}
}
//获取allure报告内容
String sendEmailText = getAllureResult(filePath);
// 创建一个Property文件对象
Properties props = new Properties();
// 设置邮件服务器的信息,这里设置smtp主机名称
props.put("mail.smtp.host", "smtp.163.com");
// 设置socket factory 的端口
props.put("mail.smtp.socketFactory.port", "465");
// 设置socket factory
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
// 设置需要身份验证
props.put("mail.smtp.auth", "true");
// 设置SMTP的端口,QQ的smtp端口是25
props.put("mail.smtp.port", "25");
// 身份验证实现
Session session = Session.getDefaultInstance(props, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
// 第二个参数,就是我网易邮箱开启smtp的授权码
return new PasswordAuthentication("Kinfe_1114@163.com", "****这里填写自己邮箱和授权码");
}
});
try {
// 创建一个MimeMessage类的实例对象
Message message = new MimeMessage(session);
// 设置发件人邮箱地址
message.setFrom(new InternetAddress("Kinfe_1114@163.com"));
// 设置收件人邮箱地址
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(addresseeEmail));
// 设置邮件主题
title = getFormatDateTime() + " " + title;
message.setSubject(title);
// 创建一个MimeBodyPart的对象,以便添加内容
BodyPart messageBodyPart1 = new MimeBodyPart();
// 设置邮件正文内容
messageBodyPart1.setText(sendEmailText);
// 创建另外一个MimeBodyPart对象,以便添加其他内容
MimeBodyPart messageBodyPart2 = new MimeBodyPart();
// 创建一个datasource对象,并传递文件
DataSource source = new FileDataSource(filePath);
// 设置handler
messageBodyPart2.setDataHandler(new DataHandler(source));
// 加载文件
/*messageBodyPart2.setFileName(filePath);*/
// 创建一个MimeMultipart类的实例对象
Multipart multipart = new MimeMultipart();
// 添加正文1内容
multipart.addBodyPart(messageBodyPart1);
// 添加正文2内容
//multipart.addBodyPart(messageBodyPart2);
// 设置内容
message.setContent(multipart);
// 最终发送邮件
Transport.send(message);
logger.info("\n邮件主题:" + title +
"\n邮件内容:" + sendEmailText +
"\n收件人邮箱:" + addresseeEmail +
"\n****************************邮件发送成功****************************");
} catch (MessagingException e) {
logger.error("邮件发送异常!");
logger.error("报错为:" + e);
}
}
/**
* 解析allure-report中suite.json文件内容
*
* @param jsonFilePath
* @return
*/
public static String getAllureResult(String jsonFilePath) {
//定义储存用例结果的容器
StringBuffer suiteResult = new StringBuffer();
int p_sum = 0; //执行成功case总数
int f_sum = 0; //执行失败case总数
int timeSum = 0; //运行总共花费时间
//存储测试方法名
Object caseName = null;
try (FileInputStream fileInputStream = new FileInputStream(jsonFilePath)) {
//获取documentContext对象
DocumentContext documentContext = JsonPath.parse(fileInputStream);
//操作documentContext读取json文件中的内容
List<LinkedHashMap<String, Object>> caseList = documentContext.read("$.children[*].children[*].children[*].children[*]");
//遍历获取到的所有测试类
HashMap<String, Object> err_Map = new HashMap<>();
for (LinkedHashMap<String, Object> linkedHashMap : caseList) {
for (Map.Entry<String, Object> entry : linkedHashMap.entrySet()) {
//获取测试方法名
if ("name".equals(entry.getKey())) {
caseName = entry.getValue();
}
//获取case执行结果状态
if ("status".equals(entry.getKey())) {
if ("passed".equals(entry.getValue())) {
p_sum++;
} else if ("failed".equals(entry.getValue())) {
//记录是失败case
err_Map.put("err_Case" + (f_sum + 1), caseName);
f_sum++;
}
}
//获取case执行时间
if ("time".equals(entry.getKey())) {
Map<String, Object> timeMap = JSONObject.parseObject(JSON.toJSONString(entry.getValue()));
Integer duration = (Integer) timeMap.get("duration");
timeSum += duration;
}
}
}
suiteResult.append("\nCase执行总数:" + (p_sum + f_sum));
suiteResult.append("\n通过:" + p_sum + "条");
suiteResult.append("\n失败:" + f_sum + "条");
suiteResult.append((f_sum != 0 ? ("\n执行失败Method:" + err_Map.toString()) : ""));
suiteResult.append("\n执行花费时间:" + (timeSum / 1000) + "秒");
logger.info("allure-report解析成功");
return suiteResult.toString();
} catch (Exception e) {
logger.error("请检查路径,获取json文件内容!");
logger.error("报错内容:" + e);
}
return null;
}
}
3.加一个util执行dos,用于初始化删除allure遗留的json文件,以及将allure.json文件通过serve开启服务,转成html文件直接访问,代码如下:
import org.apache.log4j.Logger;
import java.io.*;
/**
* @author Knife
* @description
* @createTime 2020-05-13 15:49
*/
public class OutputDos extends Rest_Perfect {
private static Logger logger = Logger.getLogger(OutputDos.class);
private static String classPath = OutputDos.class.getResource("/").getPath();
static {
//获取target根路径
classPath = classPath.substring(1, classPath.indexOf("test-classes"));
}
/**
* 输入路径(从target根路径输入):删除目录下全部文件
*
* @param path
*/
public static void delAllureResults(String path) {
File file = new File(classPath + path);
File[] files = file.listFiles();
for (File f : files) {
f.delete();
logger.info(String.format("当前文件:%s,删除成功", f));
}
}
/**
* 输入路径(从target根路径输入):results和report得到allure得html报告
*
* @param rawPath
* @param outPath
*/
public static void allureGenerateHtmlReport(String rawPath, String outPath) {
StringBuffer dos = new StringBuffer();
dos.append(String.format("cmd /c allure generate %s -o %s --clean", (classPath + rawPath), (classPath + outPath)));
//如果还有dos命令需要执行,用"&&"表示下一条
//dos.append(String.format("&& allure serve %s",(classPath + rawPath)));
try {
//执行dos命令
Process exec = Runtime.getRuntime().exec(dos.toString());
exec.waitFor();
} catch (Exception e) {
logger.error("文件路径错误,请重新输入!");
logger.error("报错内容:" + e);
}
}
}
4.编写一个class取名BaseTest,代码如下:
import cn.Knife.Wework.Utils.OutputDos;
import cn.Knife.Wework.Utils.SendEmail;
import io.qameta.allure.Description;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;
import java.util.Objects;
/**
* @author Knife
* @description
* @createTime 2020-05-13 23:03
*/
public class BaseTest {
private static OutputDos od;
private static SendEmail sendEmail = SendEmail.getInstance();
@Description("删除allure遗留的测试结果")
@BeforeSuite
public void be() {
if (Objects.isNull(od)) {
od = new OutputDos();
//运行前删除allure遗留测试结果
od.delAllureResults("/allure-results");
}
}
@Description("解析allure.json文件为report,发送邮件")
@AfterSuite
public void af() {
//解析allure的json文件为html
od.allureGenerateHtmlReport("/allure-results", "/allure-report");
sendEmail.send("接口自动化测试", "/allure-report/data/suites.json", "2538699146@qq.com");
}
}
开始测试,写一段小代码继承BaseTest,如下:
import cn.Knife.Wework.BaseTest;
import org.testng.Assert;
import org.testng.annotations.Test;
/**
* @author Knife
* @description
* @createTime 2020-05-15 1:59
*/
public class SendEmailTest extends BaseTest {
@Test
public void test1() {
String s = "我来测试了";
Assert.assertEquals(s,"我来测试了");
}
@Test
public void test2() {
String s = "我来测试了";
Assert.assertEquals(s,"我来测试了");
}
@Test
public void test3() {
String s = "我来测试了";
Assert.assertEquals(s,"我来测试了");
}
@Test
public void test4() {
String s = "我来测试了";
Assert.assertEquals(s,"我来测试了");
}
}
运行结果:
case执行完,邮件马上发送,下面看一下异常case执行会有什么效果,先增加两条异常用例,如下:
@Test
public void errTest() {
Object o = null;
Assert.assertNotNull(o);
}
@Test
public void errTestNotEquals(){
String a = "Knife";
String b = "Knife";
Assert.assertNotEquals(a,b);
}