JUnit Source Code Analysis (1)

xiaoxiao2021-03-06  13

First, the primer

The JUnit source code is the first open source project source that I read carefully. Reading the master-written code can learn some good programming styles and achieve ideas, which is an effective way to improve our programming level, so I have long wondered what these Herch's famous framework is going. Today, I will take the simplest junit to start my own source code analysis.

As the most famous unit test framework, JUnit has been completed by the two industry famous people. It has experienced multiple version upgrades (learn the JUnit foundation, JUnit practice). JUnit overall, there are many experiences worth learning from us; but there are some shortcomings, of course, this is inevitable for any procedure.

Below we will analyze the JUnit source from the overall (macro) and details (micro), the following analysis is based on

3.8.1.

Second, macro - architecture and mode

Open the source file, you will find the JUnit source code to be assigned to 6 packages: junit.awtui, junit.swingui, junit.textui, junit.extensions, junit.framework, junit.runner. The first three packages contain the entry programs for JUnit runtime and the run results display interface, which is basically transparent to JUnit users. The JUnit.Runner package contains some basic classes that support unit test runs and their own class loaders, which are completely transparent to JUnit users.

The remaining two packages are closely linked to unit testing using JUnit. The JUnit.Framework contains the written general JUnit unit test class must be used by JUnit classes; JUnit.extensions is some of the necessary extensions on the Framework package and the interface left by more features.

JUnit promotes the simplification and automation of unit testing. This requires JUnit's use to be simplified, and it is easy to implement automated testing. The entire JUnit is also probably following this premise. There are only three classes of the entire frame (shown below).

If you have a working method of Testcase, TestSuite, BaseteStrunner, then you can write test code as you wish.

Let's take a look at the relationship between JUnit.Framework, the following figure is that most of the relationships are expressed in accordance with the source code.

Let's take a look at the duties of each class. The Assert class provides a set of assertions used by JUnit, which is inherited by Testcase, and Assert has become transparent. The TEST interface is for the type of TestCase and TestSuite; and TestCase provides a method of running a unit test class; a method of loading a unit test class, a test class format, and the like is provided in TestSuite. TestResult, the name of the name is to provide a place where the test results are supplied, but it also has a controller's functionality in JUnit. The TestListener interface abstracts all the test listeners, including two ways to add errors and failed, start testing and ending tests. There are two classes in the JUnit framework to implement this interface, a Resultprinter class responsible for printed, one is the basic class BaseteStrunner class for all Testrunner (both classes are not in the framework package).

Here, it is pointed out here. The TestCase and TestResult is two-way dependencies between TestCase and TestResult, and pointed out in the relationship between the UML class diagram: the dependency is always one-way. Let us take a look at this suspicious place.

Code in TestCase:

/ **

* Runs the test case and collects the results in testResult.

* /

Public void run (test result) {// calls the RUN method in Result,

// TestResult Aspect, according to the name, should be a class that records the test results, how can I run Run?

Result.run (this);

}

Corresponding to the code in TestResult:

/ **

* Runs a testcase.

* /

Protected Void Run (Final Testcase Test) {

//start testing

Starttest (Test);

// This anonymous inside class is used for a while

Protectable P = new protectable () {

Public void protect () throws throwable {

// Tian Na, here also calls the Runbare method in Testcase

Test.Runbare ();

}

}

RunProtected (Test, P); // This method is to perform anonymous inside the above

Endtest (Test);

}

TestResult RunProtected method:

Public Void RunProtected (Final Test Test, Protectable P) {

Try {

p.Protect ();

}

Catch (assertionfailederror e) {

AddFailure (Test, E); // Add failed records for TestResult

}

Catch (ThreadDeath E) {// Don't catch threaddeath by Accident

Throw e;

}

Catch (throwable e) {

Adderror (TEST, E); // Add an error record to TestResult

}

}

Why do this strange dependency in JUnit, and TestResult in violation of a single responsibility? When I saw the TestSetup in the Junit.EXTENTIONS package, maybe I guess the author's intention. Let's take a look at the code related to TestSetup:

Public Void Run (Final TestResult Result) {

// I saw a similar anonymous internal class above.

Protectable P = new protectable () {

Public void protect () throws exception {

/ / However, this implementation in this internal class is different.

setup ();

Basicrun (Result);

TEARDOWN ();

}

}

// Call the RunProtected method in TestResult to perform the implementation above

Result.RunProtected (this, p);

}

The generation of this class is to make up for a small defect of the TestCase class (see section below). Note that there is also an anonymous internal class similar to TestResult in this class. This anonymous internal class is all the nameless implementation of the protected interface. I think there are two points here:

1) Since the internal class can be completely invisible in the next scenario, it is not used by anyone, there is also a detail of the implementation of the interface.

2) In order to improve reusability, the internal class is relatively fast. This is not necessary to perform something in your Protect method, which is wrong, failed, unusually captured code (RunProtECted method in TestResult) can be reused.

This is why there is a strange dependency as the above: For multiplexing, let the RunProtected method can be called in a TestCase and TestSetup.

However, I think it is necessary to make a good structure and readability in order to reuse, it is necessary to carefully consider it. The design estimate of JUnit is to reuse the reusability after the framework has been expanded. After finishing the problem that I puzzled. Talk about me that I think the JUnit frame is the most sighful place, that is, the small frame is used in a lot of design patterns inside. The use of these modes is also to reflect the simplicity of the entire frame structure. I will have a rough analysis as follows (please pay attention to my article about the design mode). Let's take a look at the design patterns used in Junit.framework.

Command mode: As a framework for the auxiliary unit, the developer should only care about the preparation of the test case, JUnit is just a test case executor and the result viewer, should not care too much about this framework. For JUnit, it does not need to know how to request TestCase, only as a command, and then send the execution test results to the developer. The command mode is to achieve this purpose of this delivery.

Combination mode: When the system's test case has become more, it has become a tricky problem. This is a must solve as a convenient unit test framework. So the JUnit provides the TestSuite's functionality, which allows multiple test examples to be put in a TestSuite to execute; and further support TestSuite's functionality in TestSuite. Use a combination mode to solve this problem very well.

Template mode: JUnit In TestCase this abstract class, the entire test is set, such as executing the setup method initialization test premise, run the test method, then Teardown will cancel the test settings. The specific implementation of these steps is delayed into the subclass, which is in the test class you implemented.

Template mode: JUnit In TestCase this abstract class, the entire test is set, such as executing the setup method initialization test premise, run the test method, then Teardown will cancel the test settings. The specific implementation of these steps is delayed into the subclass, which is in the test class you implemented.

转载请注明原文地址:https://www.9cbs.com/read-47877.html

New Post(0)