Developers
JUnit
Step-by-Step learning of JUnit
Author: micel casabianca
Use one of the most popular open resource testing frameworks to learn the unit test basics.
Using JUnit can greatly reduce JavaCodeMediumProgramNumber of errors. JUnit is a popular unit test framework used to perform unit tests before code is released. Now let's take a closer look at how to use tools such as JUnit, ant, and Oracle9i jdeveloper to write and run unit tests.
Why JUnit?
Most developers agree that they should be tested before the code is released, and a regression test should be performed using tools. One simple way to do this is to implement the test using the main () method in all Java classes. For example, assume that the ISO format is used (this means that there is a constructor that uses this format as the parameter and the tostring () method that returns a formatted ISO string) and a GMT time zone to compile a date subclass.Listing 1Is a simple implementation of this class.
However, this test method does not require the unit test qualifier for the following reasons:
- The minimum unit for testing in a class is the method. You should test each method separately to find out which methods work normally and which methods do not work normally.
- Methods should be tested even if the previous test fails. In this implementation, if a single test fails, subsequent tests will not run at all. This means that you do not know the percentage of bad code in your implementation.
- The test code will appear in the generated class. This may not be a problem in terms of the class size, but may become one of the security factors: for example, if your test is embedded with the database connection password, this information can be easily used in published classes.
- No framework can automatically start this test. You must write a script to start each test.
- When writing a report, you must write your own implementation and define rules to easily report errors.
The JUnit framework is designed to solve these problems. This framework is a parent class of all test instances (called "testcase") and provides tools to run the compiled test, generate reports, and define test suite ).
Let'sIsodateClass write a test: ThisIsodatetestClass is similar:
Import Java. text. parseexception; import JUnit. framework. testcase;/*** test case for <code> isodate </code>. */public class isodatetest extends testcase {public void testisodate () throws exception {isodate epoch = new isodate ("1970-01-01 00:00:00 GMT"); assertequals (0, epoch. gettime (); isodate Eon = new isodate ("01:46:40 GMT"); assertequals (000000000l * 1000, eon. gettime ();} public void testtostring () throws parseexception {isodate epoch = new isodate (0); assertequals ("00:00:00 GMT", epoch. tostring (); isodate Eon = new isodate (000000000l * 1000); assertequals ("01:46:40 GMT", eon. tostring ());}}
In this example, you should note that you have compiled an independent class for testing. Therefore, you can filter these files to avoid embedding this code in the document to be released. In addition, this example also provides a dedicated test method for each method you want to test in your code, therefore, you will know exactly which methods need to be tested, which methods are working normally, and which methods are not working properly. If you have written this test before writing the implementation document, you can use it to measure the progress of your work.
Install and run JUnit
To run this sample test instance, you must first download and install JUnit. The latest JUnit version can be found at JUnit's website.Www.junit.orgFree Download. The package is small (about KB), but includesSource codeAnd documentation. To install this program, you must first decompress the software package (junitxxx.zip ). It will create a directory (junitxxx) under which there are documents (in the doc directory) and framework application programming interface (API) documents (in the javadoc directory), the library file (JUnit. jar) and the example test instance (in the JUnit directory ). At the time of writing this article, the latest JUnit version is 3.8.1. I tested the sample in this version.
Figure 1 run the isodate Test
To run this test instance (Isodate. JavaAndIsodatetest. JavaCopy to the installation directory of JUnit, open the terminal, enter the directory, and then enter the following command line (if you are using UNIX ):
Export classpath =.:./JUnit. jarjavac *. Java or, if you are in windows, enter the following command line set classpath =.; JUnit. jarjavac *. Java
These command lines configure classpath to include classes in the current directory and the JUnit. Jar library, and compile the Java source files.
To run the test on a terminal, enter the following command line:
Java JUnit. textui. testrunner isodatetest
This command line runs the test andFigure 1The console shows the test results.
This tool can run a single test where the class name is passed to the command line. Note: Only the last test of the command line is considered. Previous tests are ignored. (It Looks Like A program error, right ?)
JUnit also provides a graphical interface that uses AWT (Abstract Window Toolkit) or swing to run the test. To run the test on the GUI, enter the following command line on the terminal:
Java JUnit. awtui. testrunner isodatetest
Or use the swing interface:
Java JUnit. swingui. testrunner isodatetest
This command line will displayFigure 2. To select a test and run it, click the button with three points. This will display the list of all tests in classpath (there are also test packages, but we will discuss it later. To run the test, click "run. The test should run correctly andFigure 2The result is displayed on the page shown in.
In this interface, you should select the check box "reload classes every run" so that the runtime can reload them before running the test classes. In this way, you can easily edit, compile, and run the test without starting the graphic interface every time.
Below the check box is a progress bar, which is very useful when running a large test package. The number of running tests, errors, and failures is displayed under the progress bar. The following is a failure list and a test hierarchy. The failure message is displayed at the bottom. Click the test hierarchy panel, and then click the "run" button in the upper-right corner of the window to run a single test method. Remember, it is impossible to use the command line tool to do this.
Note: When running a tool to start the test class, these classes must exist in classpath. However, if the test classes are stored in jar files, JUnit cannot find these test classes even if these jar files exist in classpath.
Figure 2 swing interface for running the test
This is not a convenient way to start the test, but fortunately, JUnit has been integrated into other tools (such as Ant and Oracle9i jdeveloper, to help you develop and test and make the test run automatically.
Compile a JUnit test instance
You have seen the source code of the test class asking about the implementation of isodate. Now let's study the implementation of such a test file.
The test instance is inherited by JUnit. frameword. testcase to take advantage of the advantages of the JUnit framework. The class name is to append "test" to the name of the tested class ". Because you are testing a class named isodate, the name of the test class is isodatetest. To access all methods except private methods, this class is usually in the same package as the tested class.
Note that you must write a method for each method that you want to test defined in the class. You need to test the constructor or use the ISO Date Format method. Therefore, you need to compile a test method for the constructor and tostring () method that take ISO format strings as parameters. The naming method is similar to the naming method of the test class: APPEND "test" to the method (or constructor) to be tested ".
The subject of the test method verifies assertion (assertion) to inquire about the method to be tested. For example, in the tostring () Implementation of the test method, you want to confirm that the method has a good description of the time settings (for Unix systems, it was first published at midnight on January 1, January 1, 1970 ). To implement assertion, you can use the assertion method provided by the JUnit framework. These methods are implemented in the JUnit. Framework. Assert class of the framework and can be accessed in your test because assert is the parent class of testcase. These methods can be compared with the Java keyword assert (which was newly introduced in J2EE 1.4. Some assertion methods can check whether the original types (such as Boolean and integer) are equal or between objects (use the equals () method to check whether the two objects are equal ). Other assertion Methods Check whether two objects are the same, whether an object is "null" or "non-empty", and a Boolean value (usually generated by an expression) is it true or false ". InTable 1These methods are summarized.
For assertion that uses floating-point or double-precision parameters, there is a third method, that is, using a Delta value as the parameter for comparison. In addition, the assertequals () and assertsame () methods generally do not produce the same results. (Two strings with the same value can be different because they are different objects with different memory addresses .) Therefore, assertequals () will verify the validity of assertion, while assertsame () will not. Note thatTable 1 For each assertion method in, you have another option: introduce another parameter. If the assertion fails, this parameter will provide an explanatory message. For example, assertequals (INT expected value, int actual value) can be used together with a message such as assertequals (string message, int expected value, int actual value.
When an assertion fails, the assertion method will throw an assertfailederror or comparisonfailure. Assertionfailederror is inherited by Java. Lang. error, so you do not have to declare it in the throws statement of the test method. Comparisonfailure is inherited by assertionfailederror, so you do not have to declare it. When an assertion fails, an error is thrown in the test method, so the subsequent assertion will not continue to run. After the framework captures these errors and determines that the test has failed, a message indicating the error is printed. This message is generated by assertion and transmitted to the assertion method (if any ).
Add the following statement to the end of the testisodate () method:
Assertequals ("this is a test", 1, 2 );
Compile and run the test now:
$ Javac *. java $ Java JUnit. textui. testrunner isodatetest. f. time: 0,348 there was 1 Failure: 1) testisodate (isodatetest) JUnit. framework. assertionfailederror: this is a test expected: <1> but was: <2> at isodatetest. testisodate (isodatetest. java: 29) Failures !!! Tests run: 2, failures: 1, errors: 0
JUnit prints a vertex for each processed test and displays the letter "F" to indicate a failure. A message is displayed when assertion fails. This message is composed of comments sent to the assertion method and assertion results (automatically generated ). It can be seen from this that the parameter order of the assertion method is very important for the messages generated. The first parameter is the expected value, while the second parameter is the actual value.
If an error occurs in the test method (for example, an exception is thrown ), this tool will display it as an error (instead of a "failure" caused by assertion failure "). Modify the isodatetest class to replace the preceding statement with the following statement:
Throw new exception ("this is a test ");
Then compile and run the test:
$ Javac *. java $ Java JUnit. textui. testrunner isodatetest. e. time: 0,284 there was 1 error: 1) testisodate (isodatetest) Java. lang. exception: this is a test at isodate test. testisodate (isodatetest. java: 30) Failures !!! Tests run: 2, failures: 0, errors: 1
The tool displays the exception as an error. Therefore, an error indicates an incorrect test method, rather than an incorrect test implementation.
The assert class also includes a fail () method (this version carries an explanatory message). This method will throw assertionfailederror to interrupt the running test. The Fail () method is very useful when you want a test to fail without calling a judgment method. For example, if a piece of code should throw an exception but not throw it, you can call the fail () method to fail the test. The method is as follows:
Public void testindexoutofbounds () {try {arraylist list = new arraylist (); list. get (0); fail ("indexoutofboundsexception not thrown");} catch (indexoutofboundsexception e ){}}
Advanced features of JUnit
In the sample test instance, you have run all the tests at the same time. In reality, you may want to run a given test method to ask about the implementation method you are writing, so you need to define a set of tests to run. This is the purpose of the JUnit. Framework. testsuite class of the framework. This class is actually just a container. You can add a series of tests to it. If you are implementing tostring () and want to run the corresponding test method, you can rewrite the test suite () method to notify the runner as follows:
Public Static Test Suite () {testsuite suite = new testsuite (); suite. addtest (New isodatetest ("testtostring"); Return suite ;}
In this method, you use a specific example to describe a testsuite object and add a test to it. To define a test at the method level, you can use the constructor to instantiate the test class by using the method name as a parameter. This constructor can be implemented as follows:
Public isodatetest (string name) {super (name );}
Add the constructors and methods above to the isodatetest class (JUnit. Framework. Test and JUnit. Framework. testsuite need to be introduced), and enter:
Figure 3: select a test method
$ Javac *. Java $ Java JUnit. textui. testrunner isodatetest. Time: 0, 31ok (1 test)
Note: In the test method added to the test package, only one test method is run, that is, the tostring () method.
You can also use the graphic interface to run a given test method by selecting a test method in the test hierarchy panel shown in Figure 3. However, when the test package runs once, the Panel will be filled up.
When you want to add all the test methods in a test instance to a testsuite object, you can use a dedicated constructor that uses the Class Object of the test instance as a parameter. For example, you can use the isodatetest class to implement the suite () method as follows:
Public Static Test Suite () {return New testsuite (isodatetest. Class );}
In other cases, you may want to run a set of tests that consist of other tests (such as all tests prior to project release. In this case, you must compile a class that implements the suite () method to build the test package you want to run. For example, suppose you have compiled the test classes atest and btest. To define a set of test packages that contain all tests in class atest and that are defined in btest, you can write the following classes:
Import JUnit. framework. *;/*** testsuite that runs all tests. */public class alltests {public static test suite () {testsuite suite = new testsuite ("all tests"); suite. addtestsuite (Atest. class); suite. addtest (btest. suite (); Return suite ;}}
You can run this test package just like running a single test instance. Note: If a test is added twice in a suite, the Runner runs twice (neither the test package nor the runner checks whether the test is unique ). To understand the implementation of actual test packages, we should study the test packages of JUnit itself. The source code of these classes is stored in the JUnit/test directory installed by JUnit.
Figure 4: show test results report
Adding a main () method to a test or a test package is sometimes very convenient. Therefore, you can start the test without using the runner. For example, to start the alltests test package as a standard Java program, you can add the following main () method to the class:
Public static void main (string [] ARGs) {JUnit. textui. testrunner. Run (Suite ());}
Now you can enter Java alltests to start this test package.
The JUnit framework also provides an effective way to use code, that is, to aggregate a resource to an object set called fixture. For example, the example test instance uses two reference dates called epoch and Eon. Recompiling these dates into each method test is only a waste of time (and errors may occur ). You can rewrite the test with fixture, as shown in figureListing 2.
You have defined two reference dates as test class segments and compiled them into a setup () method. This method is called before each test method. The corresponding method is the teardown () method, which clears all resources after each test method is run (in this implementation, this method does not actually do anything, because the Garbage Collector has done this for us ). Compile the test instance (the source code should be in the installation directory of JUnit) and run it:
$ Javac *. Java $ Java JUnit. textui. testrunner isodatetest2.setup () testisodate () teardown (). Setup () testtostring () teardown () Time: 0, 373ok (2 tests)
Note: A reference date is created in this test instance, so modifying these dates in any test method will not adversely affect other tests. You can put the code in these two methods to create and release the resources required for each test (such as database connection ).
The JUnit release also provides the extension mode (in the JUnit. Extensions package), that is, test decor-ators, to provide new features such as repeating a given test. It also provides a testsuite to enable you to run all tests simultaneously in an independent thread and stop when all tests in all threads are completed.
Step-by-Step learning of JUnit: Part 2