zoukankan      html  css  js  c++  java
  • 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

    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...
    ");
        }
    
        // 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);
        }
    }
    

    备注

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

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

    • JUnit的完整生命周期分为三个阶段:初始化阶段,运行阶段和结果捕捉阶段

    2.1 初始化阶段(创建TestCase及TestSuite)

    • 图中红框处,采用了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)测试运行;
    • 结束计时;
    • 结果输出;


    参考资料:

  • 相关阅读:
    VML 和 SVG 的区别
    ie神器htc
    js函数实现递归自调用的方法
    http状态码
    高级算法——贪心算法(背包问题)
    高级算法——贪心算法(找零问题)
    关于arguments.callee
    检索算法——二分查找
    检索算法——顺序查找(最大值、最小值、自组织数据)
    高级排序算法——快速排序(一种分而治之的算法)
  • 原文地址:https://www.cnblogs.com/linkworld/p/9032575.html
Copyright © 2011-2022 走看看