JUNIT4 Framework Code Parsing

Source: Internet
Author: User
Tags reflection sort

JUNIT4 has been used in the industry for a long time. Version 4 has made a lot of improvements relative to JUNIT3. Mainly for the use of annotation so that users have more customized customization, in order to provide more flexible testing methods. As early as version 3, JUnit complied perfectly with the 3 requirements of a unit test framework: Each unit test must be independent of other unit tests the errors generated in each unit test must be recorded and users can easily specify which unit tests to perform

These fine features are retained in the middle of version 4, and additional testing flexibility is added.
JUnit's code is not huge, but its high density design patterns and flexibility make the JUnit framework highly rated. As a successor to JUNIT3, it continues to have a high density design pattern, and the code is more sophisticated.    The result of using Eclipse's plug-in Codepro Analytix to measure JUnit4 is that the ratio of abstract classes and interfaces is over 22%, and the average size of each method is about 5 rows. There are already a number of articles that describe how to use the new features of JUNIT4. This article is not intended to introduce these new features, but to analyze and introduce the JUNIT4 design framework, with a version of 4.8.2. Hopefully, the reader will have at least a rudimentary understanding of junit to make it easier to understand this article.
JUNIT4 input and output:
As a program, you first need to know what its inputs and outputs are.
1. Input: JUNIT4 input is the class to be tested. The point here is that the input is the class object, not a Java object. Because the entrance to the program is Junitcore. Runclasses (CLASS<?>), that is, the parameter is a class object, not an instance of the class being tested.
2. Output: Test results, including the reasons for success and failure case, as well as the time spent on testing and so on.
The overall structure of the JUNI4:
In general, there are 2 major steps:
1. First of all, the input class uses Org.junit.runners.model.RunnerBuilder to classify and parse, and organizes it into JUNIT4 internal object Org.junit.runner.Runner.
2. Then tune Runner.run (Runnotifier) to perform testcase, and the events in the test process are handled by Runnotifier.
Organization Runner:
JUNIT4 uses the builder pattern 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.
This needs to point out that JUNIT4 uses the Alldefaultpossibilitie Sbuilder class as the director role, which is itself a runnerbuilder, by assigning corresponding characters to different class Runnerbui Lder.
The following are the classes to be measured and the corresponding runnerbuilder of the different features, and the tables that they generate Runner:


Runner Inheritance structure:
Finally, all generated runner are encapsulated into Org.junit. Runners. The suite, the suite, or the composite mode, itself is a Runner, and contains the Runner collection internally. In other words, the suite can be nested in a suite and other Runner.
What needs to be specifically described is Annotatedbuilder, which is to process the class with @RunWith to be tested and generate Runner for it. This provides a powerful feature of customer-ordered Runner. Sometimes you need to do some special functions so you can inherit Runner and then Mark @RunWith (Myrunner Class) on the category to be tested. This time Annotatedbuilder will generate an instance of Myrunne R through reflection. You can "do whatever you want" when you define your Runner, which is really cool.
JUNIT4 also brought Categories, enclosed and parameterized Runner, all of which have achieved a powerful function.
So much to say, for example, what's more obvious to a programmer than a code description:
Suppose we have JUnit3 class Version3test, JUNIT4 class Version4test, ignore class ignoretest, and Class suitetest containing static suite () methods. We put Version3test and version3test in Suite1. Then in order to show the recursive structure of the Suite1 into the Suite2, by the way Ignoretest and Suitetest also into 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 this 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 Test.run (testresult) code inside the code. Suitemethod: It inherits from Junit38classrunner. This is also an ingenious design: Suitemethod executes the static suite () method with reflection in the construction method. The return value of the suite () method is the test object, which turns the problem into a testing problem with version 3. Ignoredclassrunner: It's almost needless to say. Now that you want to ignore the test, the runner run is not executing the test content. Suite: It is the root of the composite structure, which contains a collection of all the child runner. Blockjunit4classrunner: This is a brand new design. The template mode in the original Junit.framework.TestCase.runBare () method is completely inadequate for a rich, customized test. So the concept of the statement class is introduced into the 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 test method itself is also a statement. A typical test method with @before, @After, and @test (Expected=exception.class, timeout=x) is the final form of the statement decorative chain structure: runafters-> Runbefores-> failontimeout-> expectedexception->.
Write a runner yourself:Then do something fun: Write a runner yourself. Under normal circumstances, the order in which testcase test methods are performed is to define the order of the test methods. Now we're going to write ourselves a runner that executes in ascending order of the test method name. In Blockjunit4classrunner it actually supports the sort function of dummy, and if we re implementing this sort, we can easily customize the sort 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 LU <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 finished, you will find that the order of execution is a->b->c, not the default c->b->a. about @rule:    in order to enhance the flexibility of customized behavior, JUNIT4 provides @Rule mechanism. The rule variable must implement the Org.junit.rules.MethodRule interface, and the user can do something similar to interceptor by customizing the @rule. and JUNIT4 supports multiple methodrule at the same time. There is only one method for the Methodrule interface Statement apply (Statement base, Frameworkmethod method, Object target). The parameter base is the statement that has been generated, and the Apply method allows the user to modify the existing statement base. The @Rule mechanism is so powerful that JUNIT4 has intended 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 customized for execution: @Retention (retentionpolicy.runtime) @interface runcount {int count () Default 1; /** * Define a repeatable rule. * The repeat times are defined in annotation runcount (count=x). * @author LU Repeatrule <michaellufhl@yahoo.com.cn>/class 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 that the Testit () has been executed 2 times, and the parameter statement base is actually a statement that contains modifications such as @Before and @After.

finally:

The JUNIT4 structure is huge compared to the 3 version. The code is exquisite, but the code is also quite complex, full of callback mechanisms and a large number of internal classes. Some of the more cool features of the code are under the package org.junit.experimental. For example, there are a variety of characteristics of the Runner, interested members can look at. Source code can be: 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 Sound far <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.