Junit 3.8.1 源码分析(一)

写在前面:本文基于Junit3.8.1版本,因为这是我第一次进行源码学习,先从简单的源码开始学起

1. 示例代码

1.1 准备工作
  • 下载Junit3.8.1的JAR包
  • 需要下载junit-3.8.1-sources.jarjunit-3.8.1.jar,前者是源码包,后者是项目中需要使用的Jar包;
1.2 项目中导入Junit相关jar包
  • 使用Eclipse,新建项目test;
  • test右键,选中 properties

1222878-20180513163055551-1862468762.png

1222878-20180513163110284-1235942314.png

1.3 编写示例代码
  • JUnit4之前,JUnit明确要求测试方法名以"test"开头;
  • JUnit 测试类需要继承 "TestCase";
// SampleCalculator.java,需要测试的类
public class SampleCalculator{
    // 加法
    private int add(int a, int b){
        return a + b;
    }

    // 乘法
    public int multiply(int a, int b){
        return a * b;
    }

    //除法
    public double divide(int a, int b){
        return a/b;
    }   
}

// 编写测试类,该类需要继承 TestCase
public class TestSample extends TestCase{

    private SampleCalculator cal = null;

    protected void setUp() throws Exception{
        super.setUp();
        // 每个测试方法执行前,重新new一个对象,避免测试用例之间的依赖
        cal = new SampleCalculator():
        System.out.println("在每个测试方法执行前执行 ---setUp...");
    }

    // 测试源代码的私有方法
    public void testAdd(){
        System.out.println("测试方法testAdd...");
        try{
            // 使用反射,进行私有方法的调用
            Class<SampleCalculator> clazz = SampleCalculator.class;
            Method method = clazz.getDeclaredMethod("add", new Class[] { Integer.TYPE, Integer.TYPE});
            method.setAccessible(true);
            Object obj = method.invoke(cal, new Object[]{1, 2});
            Assert.assertEquals(3, obj);
        }catch(Exception e){
            Assert.fail();
        }
    }

    // 测试乘法
    public void testMultiply(){
        System.out.println("测试方法testMultiply...");
        Assert.assertEquals.(3, cal.multiply(1, 2));
    }

    // 测试除法
    public void testDivice(){
        System.out.println("测试方法testDivide...");
        Assert.assertEquals(2, cal.divide(1, 0));
    }

    @Override
    protected void tearDown() throws Exception{
        super.tearDown();
        cal = null; // 在每个测试方法执行后,主动销毁对象
        System.out.println("在每个测试方法执行后执行--tearDown...\n");
    }

    // main方法调用
    public static void main(String[] args){
        // 以文字输出的方式,显示运行结果
        junit.textui.TestRunner.run(TestSample.class);
        // 以图形化界面的方式,显示运行结果
        // junit.swingui.TestRunner.run(TestSample.class);
        // 以图形化界面的方式,显示运行结果
        // junit.awtui.TestRunner.run(TestSample.class);
    }
}

1222878-20180513163139172-2145843560.png

备注

  • Failures:表示测试的期待结果与程序运行结果不相符;
  • Errors: 表示测试程序执行过程中,抛出了异常;

2. JUnit运行流程(DEBUG模式运行)

  • JUnit的完整生命周期分为三个阶段:初始化阶段,运行阶段和结果捕捉阶段
2.1 初始化阶段(创建TestCase及TestSuite)

1222878-20180514000435574-1176960799.png

1222878-20180514000452565-2010281525.png

1222878-20180514000604430-1425468843.png

  • 图中红框处,采用了Composite Pattern;while循环第一次,获取TestSample中的方法,
    第二次循环,获取其父类TestCase中的方法: superClass = superClass.getSuperclass();;
// TestSuite.java
public class TestSuite implements Test{

    private Vector fTests = new Vector(10);
    private String fName;

    ...(略)
    // 将符合条件的测试方法转化为TestCase,并存入到集合中
    public void addTestMethod(Method m, Vector names, Class theClass){
        String name = m.getName();
        if(names.contains(name))
            return;

        // 判断是否是公共方法
        if(!isPublicTestMethod(m)){

            // 判断是否是测试方法
            if(isTestMethod(m))
                addTest(warning("Test method isn't public: "+m.getName()));
            return;
        }
        names.addElement(name);

        // 将testXXX方法转化为 TestCase
        addTest(createTest(theClass, name));
    }

    public void addTest(Test test){
        fTests.addElement(test);
    }

    // 判断是否是公共方法
    public boolean isPublicTestMethod(Method m){
        return isTestMethod(m) && Modifier.isPublic(m.getModifiers());
    }

    // 判断是否是测试方法
    // 1. 名称以"test"开头
    // 2. 无参数,无返回值
    public boolean isTestMethod(Method m){
        String name = m.getName();
        Class[] parameters = m.getParameterTypes();
        Class returnType = m.getReturnType();
        return parameters.length == 0 && name.startWith("test") && returnType.equals(Void.TYPE);
    }

    // 根据testXXX名称,创建对应的TestCase
    static public Test createTest(Class theClass, String name){
        Constructor constructor;
        try{
            constructor = getTestConstructor(theClass);
        }catch(NoSuchMethodException e){
            ...(略)
        }
        Object test;
        try{
            if(constructor.getParameterTypes().length == 0){
                test = constructor.newInstance(new Object[0]);
                if(test instanceof TestCase)
                    ((TestCase)test).setName(name);
            }else{
                test = constructor.newInstance(new Object[]{name});
            }
        }catch(Exception e){
            ...(略)
        }
        return (Test)test;
    }
}
2.2 运行阶段(运行所有TestXXX型的测试方法)
  • 创建TestResult实例;
  • junit.textui.TestRunner的监听器fPrinter加入到result的监听器列表中(观察者模式);
  • 开始计时;
  • run(result)测试运行;
  • 结束计时;
  • 结果输出;

1222878-20180514000714461-1789927532.png


参考资料:

转载于:https://www.cnblogs.com/linkworld/p/9032575.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值