Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
kt-keystone
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
Matrix
kt-keystone
Commits
3c7867f9
提交
3c7867f9
authored
3月 11, 2022
作者:
mry
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix(base): 删除了,reportNg相关代码,添加了执行历史entity
上级
8fc71498
隐藏空白字符变更
内嵌
并排
正在显示
18 个修改的文件
包含
768 行增加
和
229 行删除
+768
-229
pom.xml
kt-base/pom.xml
+16
-32
SqlExpActuator.java
...rc/main/java/org/matrix/actuators/sql/SqlExpActuator.java
+1
-2
KtExecutionHistory.java
...n/java/org/matrix/database/entity/KtExecutionHistory.java
+38
-0
ExecutionRecordMapper.java
...ava/org/matrix/database/mapper/ExecutionRecordMapper.java
+2
-0
KtExecutionHistoryMapper.java
.../org/matrix/database/mapper/KtExecutionHistoryMapper.java
+18
-0
IKtExecutionHistoryService.java
...g/matrix/database/service/IKtExecutionHistoryService.java
+16
-0
KtExecutionHistoryServiceImpl.java
.../database/service/impl/KtExecutionHistoryServiceImpl.java
+20
-0
DataProviderForDb.java
...se/src/main/java/org/matrix/testNg/DataProviderForDb.java
+12
-8
TestPigeon.java
kt-base/src/main/java/org/matrix/testNg/TestPigeon.java
+20
-4
ExtentTestNgReporterListener.java
...ix/testNg/extentsreport/ExtentTestNgReporterListener.java
+0
-181
DataBean.java
kt-base/src/main/java/org/matrix/testNg/report/DataBean.java
+164
-0
GenerateReporter.java
.../main/java/org/matrix/testNg/report/GenerateReporter.java
+86
-0
ReportUnits.java
...e/src/main/java/org/matrix/testNg/report/ReportUnits.java
+112
-0
ReporterData.java
.../src/main/java/org/matrix/testNg/report/ReporterData.java
+78
-0
TestResultSort.java
...rc/main/java/org/matrix/testNg/report/TestResultSort.java
+15
-0
SpringUtils.java
kt-base/src/main/java/org/matrix/util/SpringUtils.java
+0
-1
overview.ftl
kt-base/src/main/resources/templates/overview.ftl
+168
-0
testng.xml
kt-script/src/main/java/org/matrix/testng.xml
+2
-1
没有找到文件。
kt-base/pom.xml
浏览文件 @
3c7867f9
...
...
@@ -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>
...
...
kt-base/src/main/java/org/matrix/actuators/sql/SqlExpActuator.java
浏览文件 @
3c7867f9
...
...
@@ -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
));
...
...
kt-base/src/main/java/org/matrix/database/entity/KtExecutionHistory.java
0 → 100644
浏览文件 @
3c7867f9
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
;
}
kt-base/src/main/java/org/matrix/database/mapper/ExecutionRecordMapper.java
浏览文件 @
3c7867f9
...
...
@@ -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
>
{
}
kt-base/src/main/java/org/matrix/database/mapper/KtExecutionHistoryMapper.java
0 → 100644
浏览文件 @
3c7867f9
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
>
{
}
kt-base/src/main/java/org/matrix/database/service/IKtExecutionHistoryService.java
0 → 100644
浏览文件 @
3c7867f9
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
>
{
}
kt-base/src/main/java/org/matrix/database/service/impl/KtExecutionHistoryServiceImpl.java
0 → 100644
浏览文件 @
3c7867f9
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
{
}
kt-base/src/main/java/org/matrix/testNg/DataProviderForDb.java
浏览文件 @
3c7867f9
...
...
@@ -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
...
...
kt-base/src/main/java/org/matrix/testNg/TestPigeon.java
浏览文件 @
3c7867f9
...
...
@@ -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
...
...
kt-base/src/main/java/org/matrix/testNg/extentsreport/ExtentTestNgReporterListener.java
deleted
100644 → 0
浏览文件 @
8fc71498
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
();
}
}
kt-base/src/main/java/org/matrix/testNg/report/DataBean.java
0 → 100644
浏览文件 @
3c7867f9
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
kt-base/src/main/java/org/matrix/testNg/report/GenerateReporter.java
0 → 100644
浏览文件 @
3c7867f9
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
kt-base/src/main/java/org/matrix/testNg/report/ReportUnits.java
0 → 100644
浏览文件 @
3c7867f9
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
kt-base/src/main/java/org/matrix/testNg/report/ReporterData.java
0 → 100644
浏览文件 @
3c7867f9
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
kt-base/src/main/java/org/matrix/testNg/report/TestResultSort.java
0 → 100644
浏览文件 @
3c7867f9
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
kt-base/src/main/java/org/matrix/util/SpringUtils.java
浏览文件 @
3c7867f9
package
org
.
matrix
.
util
;
import
com.mongodb.lang.NonNullApi
;
import
org.springframework.beans.BeansException
;
import
org.springframework.context.ApplicationContext
;
import
org.springframework.context.ApplicationContextAware
;
...
...
kt-base/src/main/resources/templates/overview.ftl
0 → 100644
浏览文件 @
3c7867f9
<?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
kt-script/src/main/java/org/matrix/testng.xml
浏览文件 @
3c7867f9
...
...
@@ -12,6 +12,6 @@
</test>
<listeners>
<listener
class-name=
"org.matrix.testNg.
extentsreport.ExtentTestNgReporterListen
er"
/>
<listener
class-name=
"org.matrix.testNg.
report.GenerateReport
er"
/>
</listeners>
</suite>
\ No newline at end of file
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论