提交 3c7867f9 authored 作者: mry's avatar mry

fix(base): 删除了,reportNg相关代码,添加了执行历史entity

上级 8fc71498
......@@ -120,37 +120,6 @@
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>com.relevantcodes</groupId>
<artifactId>extentreports</artifactId>
<version>2.41.1</version>
</dependency>
<dependency>
<groupId>com.vimalselvam</groupId>
<artifactId>testng-extentsreport</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>3.0.6</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.uncommons/reportng -->
<dependency>
<groupId>org.uncommons</groupId>
<artifactId>reportng</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
......@@ -175,12 +144,27 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
</dependencies>
<!-- https://mvnrepository.com/artifact/org.testng/testng -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.quhaodian/freemaker -->
<dependency>
<groupId>com.quhaodian</groupId>
<artifactId>freemaker</artifactId>
<version>1.8.1</version>
</dependency>
</dependencies>
<build>
......
......@@ -272,13 +272,12 @@ public class SqlExpActuator implements Actuator {
// 校验dynamicVar里的detail是否是可以直接执行的SQL
if (dynamicVar.getType() == SQL_VARIABLE && findDynamicVarList(sqlExp).size() == 0) {
// 切换数据源,执行SQL,获取数值
Set<String> dataSources = dataSourceService.switchDataSource(dataSourceDTO);
LogQueueRuntime.addNewLog(String.format("当前执行的SQL语句: %s, 使用的数据源: %s", sqlExp, dataSourceDTO));
Set<String> dataSources = dataSourceService.switchDataSource(dataSourceDTO);
log.info("当前存在的数据源 {}", dataSources);
List<Map<String, Object>> resultMap = jdbcTemplate.queryForList(sqlExp);
dataSourceService.switchMainDataSource();
return resultMap;
} else {
throw new GlobalException(String.format("动态变量的类型必须要是SQL类型且DETAIL内的SQL语句必须为元SQL语句,当前type : %s , 当前detail : %s",
dynamicVar.getType(), sqlExp));
......
package org.matrix.database.entity;
import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* <p>
*
* </p>
*
* @author mry
* @since 2022-03-11
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(value = "")
public class KtExecutionHistory extends BaseEntity {
private String unionKey;
private Long caseId;
private Long dataId;
private Long jobId;
private Integer status;
private String caseName;
private String dataName;
private String jobName;
}
......@@ -2,9 +2,11 @@ package org.matrix.database.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.matrix.database.entity.ExecutionRecord;
import org.springframework.stereotype.Repository;
/**
* @author mry
*/
@Repository
public interface ExecutionRecordMapper extends BaseMapper<ExecutionRecord> {
}
package org.matrix.database.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.matrix.database.entity.KtExecutionHistory;
import org.springframework.stereotype.Repository;
/**
* <p>
* Mapper 接口
* </p>
*
* @author mry
* @since 2022-03-11
*/
@Repository
public interface KtExecutionHistoryMapper extends BaseMapper<KtExecutionHistory> {
}
package org.matrix.database.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.matrix.database.entity.KtExecutionHistory;
/**
* <p>
* 服务类
* </p>
*
* @author mry
* @since 2022-03-11
*/
public interface IKtExecutionHistoryService extends IService<KtExecutionHistory> {
}
package org.matrix.database.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.matrix.database.entity.KtExecutionHistory;
import org.matrix.database.mapper.KtExecutionHistoryMapper;
import org.matrix.database.service.IKtExecutionHistoryService;
import org.springframework.stereotype.Service;
/**
* <p>
* 服务实现类
* </p>
*
* @author mry
* @since 2022-03-11
*/
@Service
public class KtExecutionHistoryServiceImpl extends ServiceImpl<KtExecutionHistoryMapper, KtExecutionHistory> implements IKtExecutionHistoryService {
}
......@@ -12,14 +12,13 @@ public class DataProviderForDb implements Iterator<Object[]> {
ResultSet resultSet;
ResultSetMetaData resultSetMetaData;
Boolean first = true;
public DataProviderForDb(String driver, String url
, String userName, String password, String sql) {
try {
Class.forName(driver);
Connection conn = DriverManager.getConnection(url, userName, password);
Statement createStatement = conn.createStatement();
resultSet = createStatement.executeQuery(sql);
resultSetMetaData = resultSet.getMetaData();
} catch (ClassNotFoundException | SQLException e) {
......@@ -29,13 +28,18 @@ public class DataProviderForDb implements Iterator<Object[]> {
@Override
public boolean hasNext() {
boolean flag = false;
try {
flag = resultSet.next();
} catch (SQLException e) {
e.printStackTrace();
if (first){
first = false;
return true;
}else {
boolean flag = false;
try {
flag = resultSet.next();
} catch (SQLException e) {
e.printStackTrace();
}
return flag;
}
return flag;
}
@Override
......
......@@ -13,6 +13,9 @@ import org.matrix.database.entity.TestData;
import org.matrix.database.service.ITestCaseService;
import org.matrix.database.service.ITestDataService;
import org.matrix.exception.GlobalException;
import org.matrix.socket.LogQueueRuntime;
import org.matrix.socket.TestCaseExecuteSocketPool;
import org.matrix.socket.TestExecuteType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
......@@ -25,12 +28,14 @@ import org.testng.annotations.*;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* @author mry
*/
@Component
@SpringBootTest(classes = BaseBootApplication.class)
public class TestPigeon extends AbstractTestNGSpringContextTests {
String sql;
......@@ -84,16 +89,27 @@ public class TestPigeon extends AbstractTestNGSpringContextTests {
TestCase testCase = java.util.Optional.of(caseService.getById(caseId))
.orElseThrow(() -> new GlobalException(String.format("没有找到id = %d 的TestCase", caseId)));
List<TestData> testDataList = java.util.Optional.of(dataService.list(Wrappers.lambdaQuery(TestData.class)
.eq(TestData::getTestCaseId, caseId)))
.orElseThrow(()->new GlobalException(String.format("没有找到testCaseId = %d 的TestData", caseId)));
.eq(TestData::getTestCaseId, caseId)))
.orElseThrow(() -> new GlobalException(String.format("没有找到testCaseId = %d 的TestData", caseId)));
TestCaseBTO testCaseBTO = new TestCaseBTO();
testCaseBTO.setTestCase(testCase);
for (TestData testData : testDataList){
String unionKey = UUID.randomUUID().toString();
LogQueueRuntime
.initTestCaseLog(1L
, testCase.getId()
, TestExecuteType.TEST_CASE
, unionKey
);
for (TestData testData : testDataList) {
testCaseBTO.setTestData(testData);
TestCaseExecuteResult testCaseExecuteResult = caseActuator.executeTestCase(testCaseBTO,envId, projectId);
TestCaseExecuteResult testCaseExecuteResult = caseActuator.executeTestCase(testCaseBTO, envId, projectId);
CheckPointResult checkPointResult = testCaseExecuteResult.getCheckPointResult();
Reporter.log(checkPointResult.toString());
}
//将本次产生的数据清除
TestCaseExecuteSocketPool.remove(Thread.currentThread().getId());
//将本次产生的日志从执行状态设为停止状态
LogQueueRuntime.stopExecutionRecords(unionKey);
}
@AfterMethod
......
package org.matrix.testNg.extentsreport;
import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.ResourceCDN;
import com.aventstack.extentreports.Status;
import com.aventstack.extentreports.model.TestAttribute;
import com.aventstack.extentreports.reporter.ExtentHtmlReporter;
import com.aventstack.extentreports.reporter.configuration.ChartLocation;
import com.aventstack.extentreports.reporter.configuration.Theme;
import org.testng.*;
import org.testng.xml.XmlSuite;
import java.io.File;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
/**
* @author mry
*/
public class ExtentTestNgReporterListener implements IReporter {
private static final LocalDateTime TIME = LocalDateTime.now();
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss");
private static final String STRING = DATE_TIME_FORMATTER.format(TIME);
private static final String OUTPUT_FOLDER = System.getProperty("user.dir") + "/";
private static final String FILE_NAME = STRING + "-testNg.html";
private ExtentReports extent;
@Override
public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
init();
boolean createSuiteNode = suites.size() > 1;
for (ISuite suite : suites) {
Map<String, ISuiteResult> result = suite.getResults();
//如果suite里面没有任何用例,直接跳过,不在报告里生成
if (result.size() == 0) {
continue;
}
//统计suite下的成功、失败、跳过的总用例数
int suiteFailSize = 0;
int suitePassSize = 0;
int suiteSkipSize = 0;
ExtentTest suiteTest = null;
//存在多个suite的情况下,在报告中将同一个一个suite的测试结果归为一类,创建一级节点。
if (createSuiteNode) {
suiteTest = extent.createTest(suite.getName()).assignCategory(suite.getName());
}
boolean createSuiteResultNode = result.size() > 1;
for (ISuiteResult r : result.values()) {
ExtentTest resultNode;
ITestContext context = r.getTestContext();
if (createSuiteResultNode) {
//没有创建suite的情况下,将在SuiteResult的创建为一级节点,否则创建为suite的一个子节点。
if (null == suiteTest) {
resultNode = extent.createTest(r.getTestContext().getName());
} else {
resultNode = suiteTest.createNode(r.getTestContext().getName());
}
} else {
resultNode = suiteTest;
}
if (resultNode != null) {
resultNode.getModel().setName(suite.getName() + " : " + r.getTestContext().getName());
if (resultNode.getModel().hasCategory()) {
resultNode.assignCategory(r.getTestContext().getName());
} else {
resultNode.assignCategory(suite.getName(), r.getTestContext().getName());
}
resultNode.getModel().setStartTime(r.getTestContext().getStartDate());
resultNode.getModel().setEndTime(r.getTestContext().getEndDate());
//统计SuiteResult下的数据
int passSize = r.getTestContext().getPassedTests().size();
int failSize = r.getTestContext().getFailedTests().size();
int skipSize = r.getTestContext().getSkippedTests().size();
suitePassSize += passSize;
suiteFailSize += failSize;
suiteSkipSize += skipSize;
if (failSize > 0) {
resultNode.getModel().setStatus(Status.FAIL);
}
resultNode.getModel().setDescription(String.format("Pass: %s ; Fail: %s ; Skip: %s ;", passSize, failSize, skipSize));
}
buildTestNodes(resultNode, context.getFailedTests(), Status.FAIL);
buildTestNodes(resultNode, context.getSkippedTests(), Status.SKIP);
buildTestNodes(resultNode, context.getPassedTests(), Status.PASS);
}
if (suiteTest != null) {
suiteTest.getModel().setDescription(String.format("Pass: %s ; Fail: %s ; Skip: %s ;", suitePassSize, suiteFailSize, suiteSkipSize));
if (suiteFailSize > 0) {
suiteTest.getModel().setStatus(Status.FAIL);
}
}
}
extent.flush();
}
private void init() {
//文件夹不存在的话进行创建
File reportDir = new File(OUTPUT_FOLDER);
if (!reportDir.exists() && !reportDir.isDirectory()) {
reportDir.mkdir();
}
System.out.println(FILE_NAME);
ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter(OUTPUT_FOLDER + FILE_NAME);
// 设置静态文件的DNS
htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS);
htmlReporter.config().setDocumentTitle("test report");
htmlReporter.config().setReportName("test report");
htmlReporter.config().setChartVisibilityOnOpen(true);
htmlReporter.config().setTestViewChartLocation(ChartLocation.TOP);
htmlReporter.config().setTheme(Theme.STANDARD);
htmlReporter.config().setCSS(".node.level-1 ul{ display:none;} .node.level-1.active ul{display:block;}");
extent = new ExtentReports();
extent.attachReporter(htmlReporter);
extent.setReportUsesManualConfiguration(true);
}
private void buildTestNodes(ExtentTest extenttest, IResultMap tests, Status status) {
//存在父节点时,获取父节点的标签
String[] categories = new String[0];
if (extenttest != null) {
List<TestAttribute> categoryList = extenttest.getModel().getCategoryContext().getAll();
categories = new String[categoryList.size()];
for (int index = 0; index < categoryList.size(); index++) {
categories[index] = categoryList.get(index).getName();
}
}
ExtentTest test;
if (tests.size() > 0) {
//调整用例排序,按时间排序
Set<ITestResult> treeSet = new TreeSet<>((o1, o2) -> o1.getStartMillis() < o2.getStartMillis() ? -1 : 1);
treeSet.addAll(tests.getAllResults());
for (ITestResult result : treeSet) {
Object[] parameters = result.getParameters();
StringBuilder name = new StringBuilder();
//如果有参数,则使用参数的toString组合代替报告中的name
for (Object param : parameters) {
name.append(param.toString());
}
if (name.length() > 0) {
if (name.length() > 50) {
name = new StringBuilder(name.substring(0, 49) + "...");
}
} else {
name = new StringBuilder(result.getMethod().getDescription());
}
if (extenttest == null) {
test = extent.createTest(name.toString());
} else {
//作为子节点进行创建时,设置同父节点的标签一致,便于报告检索。
test = extenttest.createNode(name.toString()).assignCategory(categories);
}
for (String group : result.getMethod().getGroups()) {
test.assignCategory(group);
}
List<String> outputList = Reporter.getOutput(result);
for (String output : outputList) {
//将用例的log输出报告中
test.debug(output);
}
if (result.getThrowable() != null) {
test.log(status, result.getThrowable());
} else {
test.log(status, "Test " + status.toString().toLowerCase() + "ed");
}
test.getModel().setStartTime(getTime(result.getStartMillis()));
test.getModel().setEndTime(getTime(result.getEndMillis()));
}
}
}
private Date getTime(long millis) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(millis);
return calendar.getTime();
}
}
package org.matrix.testNg.report;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author mruny
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DataBean {
/**
* 未执行的test数量
*/
private int excludeTestsSize;
/**
* 测试通过的数量
*/
private int passedTestsSize;
/**
* 测试失败的数量
*/
private int failedTestsSize;
/**
* 测试跳过的数量
*/
private int skippedTestsSize;
/**
* 全部执行的测试的数量
*/
private int allTestsSize;
// /**
// * 全部执行的测试方法
// */
// private ITestNGMethod[] allTestsMethod;
// /**
// * 未执行的测试方法
// */
// private Collection<ITestNGMethod> excludeTestsMethod;
/**
* 测试耗时
*/
private String testsTime;
/**
* 测试通过率
*/
private String passPercent;
/**
* 单个测试周期
*/
private String duration;
/**
* 测试用参数
*/
private String params;
/**
* 测试描述
*/
private String des;
/**
* Reporter Output
*/
private List<String> output;
/**
* 测试依赖方法
*/
private String dependMethod;
/**
* 测试异常原因
*/
private Throwable throwable;
/**
* 异常堆栈信息
*/
private StackTraceElement[] stackTrace;
/**
* 结果信息
*/
private String resultMessage;
/**
* 用例名称
*/
private String testCaseName;
/**
* 用例类型
*/
private String type;
/**
* 前置行动ID组,例如:1,2,3
*/
private String moveBefore;
/**
* 后置行动ID组,例如:1,2,3
*/
private String moveAfterCase;
/**
* 测试执行后行动ID组,例如:1,2,3
*/
private String moveAfterTest;
/**
* 是否进行异常检验,0为否,1为是
*/
private Integer abnormalCheckpoint = 0;
/**
* 是否进行非空检验,0为否,1为是
*/
private Integer noEmptyCheckpoint = 0;
/**
* 包含某字段检验(例如 张三,李四) 则对检查结果中是否包含张三或者李四
*/
private String containCheckpoint;
/**
* 不包含某字段检验(例如 张三,李四) 则对检查结果中是否不包含张三或者李四
*/
private String noContainCheckpoint;
/**
* 数据库检验点,以JSON形式存放
*/
private String databaseCheckpoint;
/**
* jsonpath检验点,以json形式存放
*/
private String jsonpathCheckpoint;
/**
* 详情参数
*/
private String detail;
}
\ No newline at end of file
package org.matrix.testNg.report;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
import org.matrix.exception.GlobalException;
import org.testng.*;
import org.testng.xml.XmlSuite;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author mruny
*/
public class GenerateReporter implements IReporter {
private static final LocalDateTime TIME = LocalDateTime.now();
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss");
private static final String STRING = DATE_TIME_FORMATTER.format(TIME);
private static final String OUTPUT_FOLDER = System.getProperty("user.dir") + "/";
private static final String FILE_NAME = STRING + "-testNg.html";
@Override
public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites,
String outputDirectory) {
try {
//freemaker的配置
Configuration cfg = new Configuration(Configuration.VERSION_2_3_28);
cfg.setClassForTemplateLoading(this.getClass(), "/templates");
cfg.setDefaultEncoding("UTF-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
//freemaker的模板文件
Template temp = cfg.getTemplate("overview.ftl");
Map context = new HashMap();
for (ISuite suite : suites) {
Map<String, ISuiteResult> suiteResults = suite.getResults();
for (ISuiteResult suiteResult : suiteResults.values()) {
ReporterData data = new ReporterData();
ITestContext testContext = suiteResult.getTestContext();
// 把数据填入上下文 测试结果汇总信息
context.put("overView", data.testContext(testContext));
//所有的测试方法
ITestNGMethod[] allTests = testContext.getAllTestMethods();
//未执行的测试方法
Collection<ITestNGMethod> excludeTests = testContext.getExcludedMethods();
IResultMap passedTests = testContext.getPassedTests();
//测试失败的测试方法
IResultMap failedTests = testContext.getFailedTests();
//测试跳过的测试方法
IResultMap skippedTests = testContext.getSkippedTests();
context.put("pass", data.testResults(passedTests, ITestResult.SUCCESS));
context.put("fail", data.testResults(failedTests, ITestResult.FAILURE));
context.put("skip", data.testResults(skippedTests, ITestResult.FAILURE));
context.put("allTest", allTests);
context.put("excludeTests", excludeTests);
}
}
//文件夹不存在的话进行创建
File reportDir = new File(OUTPUT_FOLDER);
if (!reportDir.exists() && !reportDir.isDirectory()) {
reportDir.mkdir();
}
// 输出流
FileOutputStream out = new FileOutputStream(OUTPUT_FOLDER + "/" + FILE_NAME);
Writer writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));
// 转换输出
temp.process(context, writer);
writer.flush();
} catch (Exception e) {
throw new GlobalException(e.getMessage());
}
}
}
\ No newline at end of file
package org.matrix.testNg.report;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.Reporter;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.*;
public class ReportUnits {
private static final NumberFormat DURATION_FORMAT = new DecimalFormat("#0.000");
private static final NumberFormat PERCENTAGE_FORMAT = new DecimalFormat("#0.00%");
/**
* 测试消耗时长
* return 秒,保留3位小数
*/
public String getTestDuration(ITestContext context) {
long duration;
duration = context.getEndDate().getTime() - context.getStartDate().getTime();
return formatDuration(duration);
}
public String formatDuration(long elapsed) {
double seconds = (double) elapsed / 1000;
return DURATION_FORMAT.format(seconds);
}
/**
* 测试通过率
* return 2.22%,保留2位小数
*/
public String formatPercentage(int numerator, int denominator) {
return PERCENTAGE_FORMAT.format(numerator / (double) denominator);
}
/**
* 获取方法参数,以逗号分隔
*
* @param result
* @return
*/
public String getParams(ITestResult result) {
Object[] params = result.getParameters();
List<String> list = new ArrayList<String>(params.length);
for (Object o : params) {
list.add(renderArgument(o));
}
return commaSeparate(list);
}
/**
* 获取依赖的方法
*
* @param result
* @return
*/
public String getDependMethods(ITestResult result) {
String[] methods = result.getMethod().getMethodsDependedUpon();
return commaSeparate(Arrays.asList(methods));
}
/**
* 获取全部日志输出信息
*
* @return
*/
public List<String> getAllOutput() {
return Reporter.getOutput();
}
/**
* 按testresult获取日志输出信息
*
* @param result
* @return
*/
public List<String> getTestOutput(ITestResult result) {
return Reporter.getOutput(result);
}
/*将object 转换为String*/
private String renderArgument(Object argument) {
if (argument == null) {
return "null";
} else if (argument instanceof String) {
return "\"" + argument + "\"";
} else if (argument instanceof Character) {
return "\'" + argument + "\'";
} else {
return argument.toString();
}
}
/*将集合转换为以逗号分隔的字符串*/
private String commaSeparate(Collection<String> strings) {
StringBuilder buffer = new StringBuilder();
Iterator<String> iterator = strings.iterator();
while (iterator.hasNext()) {
String string = iterator.next();
buffer.append(string);
if (iterator.hasNext()) {
buffer.append(", ");
}
}
return buffer.toString();
}
}
\ No newline at end of file
package org.matrix.testNg.report;
import org.matrix.database.entity.TestCase;
import org.matrix.database.service.ITestCaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.*;
import java.util.*;
/**
* @author mruny
*/
public class ReporterData {
// @Autowired
// private ITestCaseService testCaseService;
//
// public TestCase getTestCase(){
// }
// 测试结果Set<ITestResult>转为list,再按执行时间排序 ,返回list
public List<ITestResult> sortByTime(Set<ITestResult> str) {
List<ITestResult> list = new ArrayList<ITestResult>();
for (ITestResult r : str) {
list.add(r);
}
Collections.sort(list);
return list;
}
public DataBean testContext(ITestContext context) {
// 测试结果汇总数据
DataBean data = new DataBean();
ReportUnits units = new ReportUnits();
IResultMap passedTests = context.getPassedTests();
IResultMap failedTests = context.getFailedTests();
IResultMap skipedTests = context.getSkippedTests();
Collection<ITestNGMethod> excludeTests = context.getExcludedMethods();
int passedTestsSize = passedTests.size();
int failedTestsSize = failedTests.size();
int skipedTestsSize = skipedTests.size();
int excludeTestsSize = excludeTests.size();
//所有测试结果的数量=测试pass+fail+skip的和,因为数据驱动一个测试方法有多次执行的可能,导致方法总数并不等于测试总数
int allTestsSize = passedTestsSize + failedTestsSize + skipedTestsSize;
data.setAllTestsSize(allTestsSize);
data.setPassedTestsSize(passedTestsSize);
data.setFailedTestsSize(failedTestsSize);
data.setSkippedTestsSize(skipedTestsSize);
data.setExcludeTestsSize(excludeTestsSize);
data.setTestsTime(units.getTestDuration(context));
data.setPassPercent(units.formatPercentage(passedTestsSize, allTestsSize));
return data;
}
public List<DataBean> testResults(IResultMap map, int status) {
// 测试结果详细数据
List<DataBean> list = new ArrayList<DataBean>();
ReportUnits units = new ReportUnits();
map.getAllResults().size();
for (ITestResult result : sortByTime(map.getAllResults())) {
DataBean data = new DataBean();
data.setDuration(units.formatDuration(result.getEndMillis()
- result.getStartMillis()));
data.setParams(units.getParams(result));
data.setOutput(Reporter.getOutput(result));
data.setDependMethod(units.getDependMethods(result));
if (result.getThrowable() != null) {
data.setStackTrace(result.getThrowable().getStackTrace());
}
list.add(data);
}
return list;
}
}
\ No newline at end of file
package org.matrix.testNg.report;
import org.testng.ITestResult;
public class TestResultSort implements Comparable<ITestResult> {
private Long order;
@Override
public int compareTo(ITestResult arg0) {
return this.order.compareTo(arg0.getStartMillis());//按test开始时间排序
}
}
\ No newline at end of file
package org.matrix.util;
import com.mongodb.lang.NonNullApi;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
......
<?xml version="1.0" encoding="utf-8" ?>
<head>
<title>test</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<meta name="description" content="TestNG unit test results."/>
<style type="text/css">
body {
margin: 10px 20px;
font-size: 14px;
font-family: "Arial", "Microsoft YaHei", "黑体", "宋体", sans-serif;
}
.successBtn {
width: 60px;
padding: 3px;
background-color: #58ab48;
border-color: #58ab48;
color: #fff;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px; /* future proofing */
-khtml-border-radius: 10px; /* for old Konqueror browsers */
text-align: center;
vertical-align: middle;
border: 1px solid transparent;
font-weight: 500;
/*font-size:125%*/
}
.failBtn {
width: 60px;
padding: 3px;
background-color: #ab2e2d;
border-color: #ab2e2d;
color: #fff;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px; /* future proofing */
-khtml-border-radius: 10px; /* for old Konqueror browsers */
text-align: center;
vertical-align: middle;
border: 1px solid transparent;
font-weight: 500;
/*font-size:125%*/
}
</style>
<style>
/* Border styles */
.tabNoBorder thead, .tabNoBorder tr {
border-top-width: 1px;
border-top-style: solid;
border-top-color: rgb(211, 202, 221);
}
.tabNoBorder {
border-bottom-width: 1px;
border-bottom-style: solid;
border-bottom-color: rgb(211, 202, 221);
}
/* Padding and font style */
.tabNoBorder td, .tabNoBorder th {
padding: 5px 10px;
font-size: 14px;
font-family: Verdana;
color: rgb(95, 74, 121);
}
/* Alternating background colors */
.tabNoBorder tr:nth-child(even) {
background: rgb(223, 216, 232)
}
.tabNoBorder tr:nth-child(odd) {
background: #FFF
}
</style>
</head>
<body>
<br/>
<h2>Summary</h2>
<table id="summary" class="tabNoBorder">
<tr class="columnHeadings">
<th>用例总数</th>
<th>未执行用例数</th>
<th>执行通过</th>
<th>执行失败</th>
<th>跳过用例数</th>
<th>执行时间(s)</th>
<th>用例通过率</th>
</tr>
<tr>
<td>${overView.allTestsSize}</td>
<td>${overView.excludeTestsSize}</td>
<td>${overView.passedTestsSize}</td>
<td>${overView.failedTestsSize}</td>
<td>${overView.skippedTestsSize}</td>
<td>${overView.testsTime}</td>
<td>${overView.passPercent}</td>
<#-- <td>-->
<#-- <#list overView.allTestsMethod as item>-->
<#-- ${item.methodName}-->
<#-- </#list>-->
<#-- </td>-->
<#-- <td>-->
<#-- <#list overView.excludeTestsMethod as item1>-->
<#-- ${item1.methodName}-->
<#-- </#list>-->
<#-- </td>-->
</tr>
</table>
<br/><br/>
<h2>Detail</h2>
<table class="tabNoBorder">
<tr class="columnHeadings">
<th>编号</th>
<#-- <th>Class</th>-->
<#-- <th>MethodName</th>-->
<th>用例描述</th>
<th>执行结果</th>
<th>执行时间(s)</th>
<th>结果信息</th>
</tr>
<#assign caseNo = 0>
<#list fail as failCase>
<tr>
<#assign caseNo=caseNo+1>
<td>${caseNo}</td>
<#-- <td>${failCase.className}</td>-->
<#-- <td>${failCase.testName}</td>-->
<td>${failCase.description!}</td>
<td>
<div class="failBtn">Fail</div>
</td>
<td>${failCase.duration!}</td>
<td>${failCase.throwable!}</td>
</tr>
</#list>
<#list pass as passCase>
<tr>
<#assign caseNo=caseNo+1>
<td>${caseNo}</td>
<#-- <td>${passCase.className}</td>-->
<#-- <td>${passCase.testName}</td>-->
<td>${passCase.description!}</td>
<td>
<div class="successBtn">Success</div>
</td>
<td>${passCase.duration!}</td>
<td>${passCase.throwable!}</td>
</tr>
</#list>
</table>
<br/><br/>
</body>
</html>
\ No newline at end of file
......@@ -12,6 +12,6 @@
</test>
<listeners>
<listener class-name="org.matrix.testNg.extentsreport.ExtentTestNgReporterListener"/>
<listener class-name="org.matrix.testNg.report.GenerateReporter"/>
</listeners>
</suite>
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论