批量测试不同类里面指定版本的单元测试
每个版本的批量测试如下:修改一下版本号和对应的类名即可。(版本号需要在对应的单元测试方法上加@TestVersion(“v1.0”))
/**
* v1.0单元测试套件
* 可以指定测试类,会执行指定类里面的全部测试用例,可以指定多个class,用逗号隔开
* 使用JaCoCo进行单元测试覆盖率分析时,还需在配置中指定覆盖率包含的包
*/
public class TestSuiteOfV1_0{
/**
* 内部类指定需要测试的类和对应的方法版本号
*/
@SuiteClassesMethods(
className = {
XxxServiceImplTest.class
},
version = "v1.0")
private class TestSuite {
//v1.0对应方法的批量单元测试
}
@Test
public void testAllCases() {
TestSuiteCases.testAllCases(TestSuite.class);
}
}
单元测试上加@TestVersion注解
@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class XxxServiceImplTest {
@Autowired
private XxxService xxxService;
//可以把Mock对象添加到Spring上下文中
@MockBean
private UserService userService;
@BeforeClass
public static void setSwitch() {
//dosomething
}
@Test
@Transactional
@Rollback
@TestVersion("v1.0")
public void testUpdate() {
mockData();
xxxService.testUpdate();
}
/**
* mock数据
*/
private void mockData() {
//userService.getUser();
}
}
下面是主要的注解和工具类
/**
* @Description 测试套件(指定类的指定版本的方法)
* @Date 2021/4/22 9:56
* @Created by LIUXING
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({java.lang.annotation.ElementType.TYPE})
public @interface SuiteClassesMethods {
/**测试的类*/
Class<?>[] className();
/**类对应的测试的版本*/
String version() ;
}
/**
* @Description 单元测试版本标识
* @Date 2021/4/22 21:01
* @Created by LIUXING
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({java.lang.annotation.ElementType.METHOD})
public @interface TestVersion {
String value();
}
/**
* @Description 测试套件里面的所有指定的类和对应的方法,主要用于一个版本里面的相关方法的代码覆盖率测试
* @Date 2021/4/22 10:24
* @Created by LIUXING
*/
@Slf4j
public class TestSuiteCases {
public static <T> void testAllCases(Class<T> clazz) {
SuiteClassesMethods scm = clazz.getAnnotation(SuiteClassesMethods.class);
Class<?>[] className = scm.className();
String version = scm.version(); //版本
// 根据注解 传的方法,与每个测试类对应
Map<Class<?>, List<String>> myClassMethodMap = new LinkedHashMap();
List<List<String>> listMethodsName = new ArrayList<>();
List<String> failMethods = new ArrayList<>();
// k游标,遍历methodsName
int k = 0;
// 外层for循环,表示类个数
for (int i = 0; i < className.length; i++) {
List<String> temp = new ArrayList<>();
Method[] methods = className[i].getDeclaredMethods();
for (Method m : methods) {
TestVersion tv = m.getAnnotation(TestVersion.class);
if (tv != null && version.equalsIgnoreCase(tv.value())) {
temp.add(m.getName());
}
}
listMethodsName.add(i, temp);
myClassMethodMap.put(className[i], listMethodsName.get(i));
}
JUnitCore junitRunner = new JUnitCore();
List<Result> methodsResult = new ArrayList<>();
// 失败数
int failNum = 0;
// 成功数
int successNum = 0;
// 运行时间
long runTime = 0L;
// 运行测试方法
for (Map.Entry<Class<?>, List<String>> entry : myClassMethodMap.entrySet()) {
Class testClass = entry.getKey();
List<String> methodList = entry.getValue();
for (int i = 0; i < methodList.size(); i++) {
Request request = Request.method(testClass, methodList.get(i));
Result result = junitRunner.run(request);
runTime += result.getRunTime();
// 只添加失败的
if (result.wasSuccessful()) {
successNum++;
} else {
failNum++;
failMethods.add(methodList.get(i));
methodsResult.add(result);
}
}
}
log.info("单元测试全部方法列表:{}", JSONObject.toJSONString(listMethodsName));
if (failMethods.size() > 0) {
log.info("单元测试失败方法列表:{}", JSONObject.toJSONString(failMethods));
}
//打印结果
printTestResults(clazz.getName(), failNum, successNum, runTime);
}
private static void printTestResults(String className, int failNum, int successNum, long runTime) {
StringBuilder sb = new StringBuilder();
sb.append("===================== 结果集 =====================");
sb.append("\n");
sb.append("用例总数:" + (successNum + failNum));
sb.append(", 成功数:" + successNum);
sb.append(", 失败数:" + failNum);
sb.append(", 运行时间:" + (runTime / 1000) / 60 + " 分钟 " + (runTime / 1000) % 60 + " 秒");
sb.append("\n");
sb.append("=================================================");
sb.append("\n");
sb.append("\n");
log.info("{} 单元测试>>>>>>>>>>>>>>>\n {}", className, sb);
}
}