设置密码

验证码错误,请重新填写

免费建站旅程马上开始

开始建站
建站中

已有帐号?直接登录

首页>森动学院>网站建设教程 > 自定义JUnit测试类
自定义JUnit测试类
发布时间: 2014-06-24
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)