JUNIT4 Framework Code Parsing

Source: Internet
Author: User
Tags reflection sort

JUNIT4 has been used in the industry for a long time. In contrast to JUNIT3, version 4 has made a lot of improvements. Mainly for the use of annotation so that users have more customized customization, in order to provide more flexible testing means. As early as version 3, JUnit perfectly conforms to the 3 requirements of a unit testing framework: Each unit test must be independent of the other unit tests the errors produced in each unit test must be logged. User can easily specify unit tests to execute

In the middle of version 4 these excellent features were retained, and more testing flexibility was added.
JUnit's code is not huge, but its high-density design patterns and flexibility make it highly rated for the JUnit framework. As a follow-up version of JUNIT3 it continues the style of high-density design patterns, and the code is more sophisticated.    The result of using Eclipse's plug-in Codepro Analytix to measure JUnit4 is that the proportion of abstract classes and interfaces exceeds 22%, and the average size of each method is approximately 5 rows. There are already many articles describing how to use the new features of JUNIT4. This article does not intend to introduce these new features, but only analyzes and introduces the design framework of JUNIT4, which is version 4.8.2. Readers are expected to have at least a preliminary understanding of junit in order to be able to understand this article more easily.
JUNIT4 input and output:
As a program, you first need to know what its input and output are.
1. Input: The input of the JUNIT4 is the class to be tested. What you need to explain here is that the input here is the class object, not a Java object. Because the entrance to the program is Junitcore. Runclasses (class<?> ...), which means that the parameter is a class object, not an instance of the class to be tested.
2. Output: The result of the test, including the reason for the successful and failed case, and the time spent on the test.
The overall structure of the JUNI4:
In general, it can be divided into 2 major steps:
1. First, the input class uses Org.junit.runners.model.RunnerBuilder to classify and parse it into JUNIT4 internal object Org.junit.runner.Runner.
2. Then tune Runner.run (Runnotifier) to perform the testcase, and the events during the test are handled by Runnotifier.
Organization Runner:
JUNIT4 uses the builder mode to generate Runner. In this process, Runnerbuilder's subclasses play a specific builder role. A runnerbuilder is responsible for the generation of a Runner, and each Runner represents a class to be tested.
The need to point out is that JUNIT4 uses the Alldefaultpossibilitie Sbuilder class as the role of director, which is itself a runnerbuilder, it assigns the corresponding by the different class characteristics. Runnerbui Lder.
The following are the different characteristics of the class to be tested and the corresponding Runnerbuilder, as well as the table of its generated Runner:


Inheritance structure of Runner:
Finally, all the generated runner are encapsulated into the org.junit. Runners. Suite, Suite or composite mode, which is itself a Runner, and contains the Runner collection internally. That means you can nest suite and other Runner inside the suite.
A special note is Annotatedbuilder, which deals with the class to be tested with @RunWith and generates Runner for it. This provides a powerful feature for custom Runner. Sometimes you need to do some special functions you can inherit Runner and then label @RunWith (Myrunner. Class) on the classes to be tested. This time Annotatedbuilder will generate an instance of Myrunne R through reflection. When you define your own Runner, you can "do whatever you like" to test the behavior, which is really cool.
JUNIT4 also brought Categories, enclosed and parameterized to the Runner, all of which achieved powerful functionality.
It is better to say so than to cite an example of what is better for a programmer than to use a code description:)
Suppose our test class has JUnit3 class Version3test, JUNIT4 class Version4test, ignore class ignoretest, and class suitetest containing the static suite () method. We put Version3test and version3test in Suite1. Then in order to show the recursive structure put Suite1 into Suite2, by the way Ignoretest and Suitetest also put Suit E2.

The code is as follows:
public class Version3test extends testcase{public void testin3x () {}} public class Version4test {@Test public void Testi N4x () {}} @RunWith (Suite.class) @Suite. suiteclasses ({version3test.class, version4test.class}) public class Suite1 {} @i Gnore public class Ignoretest {public void Testinignore () {}} public class Suitetest {public static Test suite () {return New TestSuite (); }} @RunWith (Suite.class) @Suite. suiteclasses ({//put All together Suite1.class, Ignoretest.class, Suitetest.class}) public class Suite2 {}
If you are running Suite2 under Eclipse, you can see the structure:description of various runner:Junit38classrunner: Its run method is actually to move the 3 version of the operating mechanism to the 4 version. You can see code like Test.run (TestResult) in the code. Suitemethod: It inherits from Junit38classrunner. This is also a clever design: Suitemethod will use reflection to execute the static suite () method within the construction method. The return value of the suite () method is the test object, which turns the problem into a testing issue for version 3. Ignoredclassrunner: It's almost needless to say. Since you want to ignore the test, then this runner run is not executing the test content. Suite: It is the root of the composite structure, and it contains a collection of all the child runner. Blockjunit4classrunner: This is a brand new design. The template pattern in the original Junit.framework.TestCase.runBare () method is completely inadequate for testing that provides a rich set of customized tests. So the concept of the statement class is introduced in Blockjunit4classrunner, which is actually a decorator pattern. Statement there is only one method evaluate (). A method evaluate () represents an action: for example, @before is a statement, @BeforeClass is also a statement, and the expected and timeout defined in @Tes t are statement. Of course the method being tested is itself a statement. A typical test method with @before, @After, and @test (Expected=exception.class, timeout=x) consists of a statement decorative linked list structure: runafters Runbefores, Failontimeout, ExpectedException, InvokeMethod.
Write a runner yourself:Then do something fun: Write a runner yourself. Under normal circumstances, the order in which the TestCase test methods are executed is to define the order of the test methods. Now we write ourselves a runner that is executed in ascending order by the name of the test method. In Blockjunit4classrunner it will actually support the sort function of dummy, and if we re-implement this sort it will be easy to customize the sorting behavior. Although this is contrary to the principle that unit tests are independent of each other, for fun:)/** * The Runner provides sort functionality by Lexicographic test method name. * * @author Lo <michaellufhl@yahoo.com.cn> * * public class Sortrunner extends Blockjunit4classrunner {/** * Create A Sorter. * @param Klass * @throws initializationerror * * Public Sortrunner (Class<?> Klass) throws Initializationerror {Super (Klass); Sorter Sorter = new Sorter (new comparator<description> () {public int compare (Description O1, Description O2) {Retu RN O1.getmethodname (). CompareTo (O2.getmethodname ()); }}); Sort (sorter); }} @RunWith (Sortrunner.class) public class Version4test {@Test public void C () {} @Test public void A () {} @Test public Vo ID B () {}}
When execution is complete, you will find that the execution order is a->b->c, not the default c->b->a. about @rule:    to enhance the flexibility of custom behavior, JUNIT4 provides a @Rule mechanism. The rule variable must implement the Org.junit.rules.MethodRule interface, and the user can do something like interceptor by customizing the @rule. and JUNIT4 supports multiple methodrule at the same time. The Methodrule interface has only one method Statement apply (Statement base, Frameworkmethod method, Object target). The parameter base is the statement that has been generated, and the user can modify the existing statement base by using the Apply method. The @Rule mechanism is so powerful that JUNIT4 already intends to implement the Expectingexception,timeout,before and after features with the rule mechanism in subsequent versions.    continue to do something interesting: Define a rule that can be custom executed: @Retention (retentionpolicy.runtime) @interface runcount {int count () Default 1; }/** * Define a repeatable Rule. * The repeat times is defined in annotation runcount (count=x). * * @author Lo <michaellufhl@yahoo.com.cn> * * Class Repeatrule implements Methodrule {public final Statement apply ( Final Statement base, Final Frameworkmethod method, Object target) {return new Statement () {@Override public void Evalua Te () throws throwable {int count =1;//default runcount rcount= method.getannotation (Runcount.class); if (rcount! = null) Count=rcount.count (); while (Count-->0) {base.evaluate ();}} }; }} public class Repeattest {@Rule public repeatrule Rule = new Repeatrule (), @Test @RunCount (count=2)//run twice public void Testit () {}}
You can see Testit () executed 2 times, and the parameter statement base is actually a statement that contains the decorations of @Before and @After.

finally:

The JUNIT4 structure is huge compared to the 3 version. The code is very delicate, but the code is also quite complex, full of callback mechanisms and a large number of internal classes. There are some cool features of the code below the package org.junit.experimental. For example, there are various characteristics of the Runner, interested people can see. Source code can go to: Https://github.com/downloads/KentBeck/junit/junit-4.8.2.jar download.

Resources:
JUnit A Cook ' s tour junit 4 in Seconds
JUnit in Action:vincent Massol, Ted husted

Author: Lu Zhiyuan <michaellufhl@yahoo.com.cn>

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.