Junit源码阅读_textui_testrunner

2021-07-06
halley.fang

junit可以通过命令行进行执行,java -ea junit.textui.TestRunner testclass 这样的形式,本文主要就是阅读 junit.textui.TestRunner 的源码。

源码解读

加载→运行

首先找到junit的入口类

入口类
Figure 1. main方法
public static void main(String[] args) {
    TestRunner aTestRunner = new TestRunner();
    try {
      //start传入测试类
        TestResult r = aTestRunner.start(args);
        if (!r.wasSuccessful()) {
            System.exit(FAILURE_EXIT);
        }
        System.exit(SUCCESS_EXIT);
    } catch (Exception e) {
        System.err.println(e.getMessage());
        System.exit(EXCEPTION_EXIT);
    }
}

start分析命令行参数并运行测试类的suite

public TestResult start(String[] args) throws Exception {
        String testCase = "";
        String method = "";
        boolean wait = false;

        for (int i = 0; i < args.length; i++) {
            if (args[i].equals("-wait")) {
                wait = true;
            } else if (args[i].equals("-c")) {
                testCase = extractClassName(args[++i]);
            } else if (args[i].equals("-m")) {
                String arg = args[++i];
                int lastIndex = arg.lastIndexOf('.');
                testCase = arg.substring(0, lastIndex);
                method = arg.substring(lastIndex + 1);
            } else if (args[i].equals("-v")) {
                System.err.println("JUnit " + Version.id() + " by Kent Beck and Erich Gamma");
            } else {
                testCase = args[i];
            }
        }

        if (testCase.equals("")) {
            throw new Exception("Usage: TestRunner [-wait] testCaseName, where name is the name of the TestCase class");
        }

        try {
            if (!method.equals("")) {
                return runSingleMethod(testCase, method, wait);
            }
            //初始化,获取testSuite
            Test suite = getTest(testCase);
            //测试运行
            return doRun(suite, wait);
        } catch (Exception e) {
            throw new Exception("Could not create and run test suite: " + e);
        }
    }
public Test getTest(String suiteClassName) {
        if (suiteClassName.length() <= 0) {
            clearStatus();
            return null;
        }
        Class<?> testClass = null;
        try {
          //根据类名获取测试类信息
            testClass = loadSuiteClass(suiteClassName);
        } catch (ClassNotFoundException e) {
            String clazz = e.getMessage();
            if (clazz == null) {
                clazz = suiteClassName;
            }
            runFailed("Class not found \"" + clazz + "\"");
            return null;
        } catch (Exception e) {
            runFailed("Error: " + e.toString());
            return null;
        }
        Method suiteMethod = null;
        try {
          //获取所有测试方法信息
            suiteMethod = testClass.getMethod(SUITE_METHODNAME);
        } catch (Exception e) {
            // try to extract a test suite automatically
            clearStatus();
            //没有通过getMethod方法拿到suiteMethod的话,就会调用TestSuite构造器
            return new TestSuite(testClass);
        }
        if (!Modifier.isStatic(suiteMethod.getModifiers())) {
            runFailed("Suite() method must be static");
            return null;
        }
        Test test = null;
        try {
            test = (Test) suiteMethod.invoke(null); // static method
            if (test == null) {
                return test;
            }
        } catch (InvocationTargetException e) {
            runFailed("Failed to invoke suite():" + e.getTargetException().toString());
            return null;
        } catch (IllegalAccessException e) {
            runFailed("Failed to invoke suite():" + e.toString());
            return null;
        }

        clearStatus();
        return test;
    }
public TestSuite(final Class<?> theClass) {
        addTestsFromTestCase(theClass);
    }

    private void addTestsFromTestCase(final Class<?> theClass) {
        fName = theClass.getName();
        try {
            getTestConstructor(theClass); // Avoid generating multiple error messages
        } catch (NoSuchMethodException e) {
            addTest(warning("Class " + theClass.getName() + " has no public constructor TestCase(String name) or TestCase()"));
            return;
        }

        if (!Modifier.isPublic(theClass.getModifiers())) {
            addTest(warning("Class " + theClass.getName() + " is not public"));
            return;
        }

        Class<?> superClass = theClass;
        List<String> names = new ArrayList<String>();
        //判断superClass是不是Test类的子类
        while (Test.class.isAssignableFrom(superClass)) {
          //用迭代的形式从被测试的类开始,到被测试的类继承的TestCase,最后到Object类,这个循环从这几个类中所有符合条件的测试方法加入到名为names的list中
            for (Method each : MethodSorter.getDeclaredMethods(superClass)) {
                addTestMethod(each, names, theClass);
            }
            superClass = superClass.getSuperclass();
        }
        if (fTests.size() == 0) {
            addTest(warning("No tests found in " + theClass.getName()));
        }
    }
private void addTestMethod(Method m, List<String> names, Class<?> theClass) {
        String name = m.getName();
        if (names.contains(name)) {
            return;
        }
        //判断是否public,非public判断为true
        if (!isPublicTestMethod(m)) {
          //判断非public方法是否startsWith("test")
            if (isTestMethod(m)) {
                addTest(warning("Test method isn't public: " + m.getName() + "(" + theClass.getCanonicalName() + ")"));
            }
            return;
        }
        names.add(name);
        addTest(createTest(theClass, name));
    }

至此测试方法初始化完成,接下来就是 dorun

public TestResult doRun(Test suite, boolean wait) {
    TestResult result = createTestResult();
    //添加结果打印监听
    result.addListener(fPrinter);
    //开始执行时间
    long startTime = System.currentTimeMillis();
    //执行测试
    suite.run(result);
    //执行结束时间
    long endTime = System.currentTimeMillis();
    //执行耗时
    long runTime = endTime - startTime;
    fPrinter.print(result, runTime);

    pause(wait);
    return result;
}
run实现
Figure 2. test run实现
public void run(TestResult result) {
  //执行TestResult run
    result.run(this);
}
protected void run(final TestCase test) {
  //开始执行
    startTest(test);
    Protectable p = new Protectable() {
        public void protect() throws Throwable {
            //test执行方法
            test.runBare();
        }
    };
    //调用执行并获取测试结果
    runProtected(test, p);
    //执行结束
    endTest(test);
}
public void runBare() throws Throwable {
        Throwable exception = null;
        //执行前置
        setUp();
        try {
            //调用执行方法
            runTest();
        } catch (Throwable running) {
            exception = running;
        } finally {
            try {
                //执行后置
                tearDown();
            } catch (Throwable tearingDown) {
                if (exception == null) exception = tearingDown;
            }
        }
        if (exception != null) throw exception;
    }

    protected void runTest() throws Throwable {
        assertNotNull("TestCase.fName cannot be null", fName); // Some VMs crash when calling getMethod(null,null);
        Method runMethod = null;
        try {
            // use getMethod to get all public inherited
            // methods. getDeclaredMethods returns all
            // methods of this class but excludes the
            // inherited ones.
            runMethod = getClass().getMethod(fName, (Class[]) null);
        } catch (NoSuchMethodException e) {
            fail("Method \"" + fName + "\" not found");
        }
        if (!Modifier.isPublic(runMethod.getModifiers())) {
            fail("Method \"" + fName + "\" should be public");
        }

        try {
            //执行
            runMethod.invoke(this);
        } catch (InvocationTargetException e) {
            e.fillInStackTrace();
            throw e.getTargetException();
        } catch (IllegalAccessException e) {
            e.fillInStackTrace();
            throw e;
        }
    }

Similar Posts

上一篇 Junit用法

Comments

Table of contents