JUnit是常用单元测试工具,如果希望跳过某个测试类,一般在类上面添加@Ignore注解。实际情况下,经常遇到某些测试类在符合某些条件时需要运行、不符合时又不需要运行的情况,频繁加减@Ignore注解的话相当繁琐。有没有办法,能根据自己的配置文件,灵活决定是否运行某些测试类呢?
接下来定义我们模拟的JUnit类,这里为了方便我将所有能用到的都写在一个MyJUnit类中。他对外只有一个构造方法和一个run方法。还有一个对比用的assertEquals方法
[java] view plaincopy
public class MyJUnit {
// 存放所有标注了before注解的集合
private List<Method> beforeMethod;
// 存放所有标注了after注解的集合
private List<Method> afterMethod;
// 存放所有标注了test注解的集合
private List<Method> testMethod;
// 存放需要捕捉的异常集合
private static List<Exception> exceptions;
// 被测试类的实例化对象
private Object object;
// 被测试类的Class对象
private Class<?> testClass;
//自定义MyJUnit类的构造方法,用于接收被测试类的名字然后初始化需要的变量和方法
public MyJUnit(String testName) {
super();
try {
beforeMethod = new ArrayList<>();
afterMethod = new ArrayList<>();
testMethod = new ArrayList<>();
exceptions = new ArrayList<>();
//使用反射根据传递的类名生成对象
testClass = Class.forName(testName);
object = testClass.newInstance();
//获取所有的方法并根据注解进行分类
getAllMethods();
} catch (Exception e) {
e.printStackTrace();
}
}
// 根据注解获取所有的方法
private void getAllMethods() {
Method[] methods = testClass.getMethods();
for (Method m : methods) {
// 找到被before修饰的方法,放入before方法的集合中
if (m.isAnnotationPresent(Before.class)) {
beforeMethod.add(m);
}
// 找到被After修饰的方法,放入after方法的集合中
if (m.isAnnotationPresent(After.class)) {
afterMethod.add(m);
}
// 找到被test修饰的方法,放入test方法的集合中
if (m.isAnnotationPresent(Test.class)) {
testMethod.add(m);
}
}
}
// run方法
public void run() {
// 运行所有的测试方法
for (Method method : testMethod) {
runTest(method);
}
// 判断捕捉的异常集合,如果大小为0则没有异常,测试通过。有异常则表示测试不通过并打印异常信息
if (exceptions.size() == 0) {
System.out.println("通过测试");
} else {
for (Exception e : exceptions) {
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
System.out.println("测试不通过,错误的内容为:");
e.printStackTrace();
}
}
}
// 按照before test after的顺序执行
private void runTest(Method method) {
try {
runBefores();
runTestMethod(method);
runAfters();
} catch (Exception e) {
e.getMessage();
throw new RuntimeException(
"test should never throw an exception to this level");
}
}
// 执行所有after标注的方法
private void runAfters() throws Exception {
for (Method m : afterMethod) {
m.invoke(object, new Object[] {});
}
}
// 执行所有before标注的方法
private void runBefores() throws Exception {
for (Method m : beforeMethod) {
m.invoke(object, new Object[] {});
}
}
// 执行test方法
private void runTestMethod(Method method) {
// 判断测试是否通过的标志
boolean passCheck = false;
try {
// 获得Test注解
Test testAnnotation = method.getAnnotation(Test.class);
// 判断test注解标注的属性是否为需要的类型,这里可以根据需要加入不同的判断条件
if (testAnnotation.expected().newInstance() instanceof Exception) {
passCheck = true;
}
method.invoke(object);
} catch (Exception e) {
// 判断通过则测试通过,否者将异常加入到异常集合中
if (passCheck) {
return;
} else {
addExceptions(e);
}
}
}
private static void addExceptions(Exception e) {
exceptions.add(e);
}
// 自定义的assertEquals方法,判断两个值是否相等,可以根据需要加入更多类型的判断,如果相等则通过,否则new一个异常加入到异常集合中
static public void assertEquals(Object expected, Object actual) {
if (expected.equals(actual)) {
return;
} else {
addExceptions(new Exception("预期值与实际值不相等"));
}
}
}
注解和JUnit类都定义好后可以写测试的方法了,和之前的测试方法没有区别,只是这次导包导入的都是我们自定义的包。
[java] view plaincopy
import static gxy.test.Junit.MyJUnit.*;
public class MyCalulateTest {
private Calculate cal;
@Before
public void before() throws Exception {
cal = new Calculate();
System.out.println("------------------");
System.out.println("before test");
}
@After
public void after() throws Exception {
System.out.println("after test");
}
@Test
public void addTest() {
System.out.println("do add test");
int result = cal.add(10, 20);
// 这里的预期值为40,实际为30,所以这个方法通过不了测试
assertEquals(40, result);
}
@Test(expected = Exception.class)
public void divTest() throws Exception {
System.out.println("do divide test");
// 调用1除以0,抛出异常
cal.divide(1, 0);
}
}
为了检验测试效果,这里对于addTest的方法中assertEquals方法传入的预期值和实际值不同。
下面看最后的运行类。
[java] view plaincopy
public static void main(String[] args) throws Exception {
MyJUnit myJUnit = new MyJUnit("gxy.test.Junit.MyCalulateTest");
myJUnit.run();
}
只有2行代码,传入需要测试的类的名字,然后执行run方法。
测试结果:
------------------
before test
do add test
after test
------------------
before test
do divide test
after test
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
测试不通过,错误的内容为:
java.lang.Exception: 预期值与实际值不相等
at gxy.test.Junit.MyJUnit.assertEquals(MyJUnit.java:139)
at gxy.test.Junit.MyCalulateTest.addTest(MyCalulateTest.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at gxy.test.Junit.MyJUnit.runTestMethod(MyJUnit.java:119)
at gxy.test.Junit.MyJUnit.runTest(MyJUnit.java:85)
at gxy.test.Junit.MyJUnit.run(MyJUnit.java:66)
at gxy.test.Junit.FinalTest.main(FinalTest.java:13)