Junit actual combat (2)
Amender: Huang Kai
E_mail: hk_sz@163.com
Third, installation
1. Get the JUnit package, download the latest packages from junit (http://www.junit.org/index.htm or http://download.sourceforge.net/junit/). Here I am using http://download.sourceforge.net/junit/junit2.zip.
2. Unpack it in the appropriate directory (I installed D: / JUnit2). This is in the installation directory (that is, you have selected the directory you choose). You find a file named JUnit.jar. Add this JAR file to your ClassPath system variable. (Ide's settings will be different, see the Configuration Guide for your favorite IDE) JUnit is installed.
Fourth, run
Through the previous introduction, we have a probably contour for Junit. I know what it is doing. Let us now rewrite the test class TestCar to make it conform to the JUnit specification - can run in JUnit.
// Execute the test class (JUnit version)
Import junit.framework. *;
Public Class Testcar Extends Testcase
{
Protected int expectedwheels;
protected car mycar;
Public testcar (String name)
{
Super (Name);
}
protected void setup ()
{
EXPECTEDWHEELS = 4;
Mycar = new car ();
}
Public Static Test Suite ()
{
/ ** The Type Safe Way * /
/ *
Testsuite suite = new testsuite ();
Suite.addtest
New Testcar ("Car.Getwheels")
{
Protected void runtest ()
{
TestGetwheels ();
}
}
);
Return suite;
* /
/ ** the dynamic way * /
Return New TestSuite (TestCar.class);
}
Public void testGetwheels ()
{
Assertequals (expectedwheels, mycar.getwheels ());
}
}
The TestCar after the revision has faced unrecognizable. Let us first understand what these changes have mean, and then see how this test is implemented.
1> Import statement, introduce the class of JUnit. (is that OK)
2> Inherited Testcase. A TestCase can be treated as a collection of methods for testing a class. For details, please refer to JUnit Information
3> Setup () Sets the task of initialization. We will see SETUP will have special use.
4> TestGetWheeeels () compares the value of the expected value and mycar.getwheels () and prints the result of the comparison. Assertequals is the method defined in junit.framework.assert, and junit.framework.testcase inherits JUnit.Framework.Assert.
5> Suite () is a very special static method. JUnit's Testrunner calls the Suite method to determine how many tests can be executed. The above example shows two methods: static method is to construct an internal class and use the constructor to name the test (Test Name, such as Car.Getwheels), which covers the runtest () method, indicating that the test needs to be executed. Those methods - TestGetWheels (). The dynamic approach is to use the internal province to implement RUNTEST () to find out those tests that need to be implemented. At this time, the name of the test is the name of the test method (Test Method, such as TestGetWheels). JUnit will automatically find and call this class's test method. 6> Watch TestSuite as a container for parcel test. If the test is tested as a leaf node, TestSuite is a branch node. In fact, Testcase, TestSuite, and TestSuite make up a Composite Pattern. One of JUnit's documentation has a special explanation how to use the Pattern constructed JUnit framework. Interested friends can view JUnit information.
How to run this test? Handmade method is to type the following command:
[Windows] d: /> java junit.textui.teestrunner testcar
[UNIX]% junit.textui.teestrunner testcar
Don't worry about the character of you want to knock, in the future, as long as you have a few mice. The result of the operation should be as follows, indicating a test and passed the test:
.
Time: 0
OK (1 tests)
If we modify the value returned in Car.GetWheels () to 3, simulate an error, you will get the following results:
.F
Time: 0.16
Failures !!!
Test Results:
Run: 1 Failures: 1 Errors: 0
There WAS 1 Failure:
1) TestCar.testGetwheels "Expected: <3> But Was: <4>"
Note: Dices on Time represent the number of tests, if the test is passed, OK is displayed. Otherwise, the rear side of the dot is marked, indicating that the test failed. Note that in an emulated error test, we will get a detailed test report "Expected: <3> But Was: <4>", which is enough to tell us where the problem happens. Here is the process of debugging, testing, debugging, testing, until you get the expected result.
5. Design by Contract (this sentence I can't translate)
Design by Contract This is a design technology developed by Bertrand Meyer (founder of the Eiffel language). I found that using Design by Contract in JUnit will bring unexpected effects. The core of Design by Contract is an assession. As an assertion is a Boolean sentence, the statement cannot be false. If it is a fake, it indicates a bug. Design by Contract uses three assertions: pre-conditions, post-conditions and invariant (Invariants), not intended to discuss details of Design by Contract, but hope to in the test Can play its role. The front condition can be used to determine if the test is allowed to enter the test before performing the test. Such as Expectedwheels> 0, MyCar! = NULL. The rear condition is used to determine whether the test results are correct after the test execution. Such as expectedwheels == mycar.getWheels (). The invariance is particularly useful in judging the consistentness of the transaction. I hope that Junit can enhance the Design by Contract as an enhancement of future versions.
Sixth, refactoring (this sentence I still can't translate)
Refactoring has not been directly connected with the test, but is related to software entropy, but since we say that we say that test can solve software entropy problems, we must say a solution. (Only the software entropy can only be found, and Refactoring can solve the problem of software entropy.) Software entropy brings a problem: Do you need to redesign the structure of the entire software? In theory, this should be, but reality is not allowed to do this. This is or due to the reason, or due to the reason. The structure of redesigning the entire software will bring us short-term pain. Keeping a patch to make the software to make us long-term pain. (No matter what, we always be in hot and hot)
Refactoring is a term for describing a technology that we can avoid short-term pain brought about by reconstructing the entire software. When you refactor, you don't change the functionality of the program, but change the structure inside the program so that it is easier to understand and use. Such as: The name of the method will move a member variable from a class to another, and the two similar methods are abstracted into the parent class. Every step made is small, but the 1-2 hours of Refactoring work makes your program structure more suitable for the current situation. Refactoring has some rules:
1> Do not refactor existing code while adding new features. There must be a clear boundaries between the two. If you add new features, the rest of the time is added to the rest of the time.
2> Before you start refactoring, you must ensure that the test can be passed successfully, otherwise refactoring has no meaning;
3> Small refactoring, big is not refactoring. If you intend to refactor the entire software, there is no need to refactoring. Refactoring is only necessary to add new features and debug bugs. Don't wait until the last level of the delivery software is refactoring. That is not the difference between the patch. Refactoring can also display its power in the regression test. To understand, I don't oppose the patch, but I have to remember that the patch is the supreme trick that should be used. (Patching also requires a high technology, please refer to Microsoft website) Seven, IDE supports JUnit support
Java IDE currently supporting JUnit includes
Idea
the way
Score (1-5, full 5)
Forte for Java 3.0 Enterprise Edition
Plug-in
3
JBUILDER 9 Enterprise Edition
Integrated with IDE
4
Visual Age for Java
Support
N / a
How to use JUnit in IDE is a very specific thing. Different IDEs have different ways of use. Once you understand the nature of JUnit, it is easy to use. So we don't rely on specific IDE, but concentrate on how to use JUnit to write unit test code. Anxious people can see the information.
Eight, small knot
Once you have installed JUnit, you may want to try our Car and TestCar classes, no problem, I have already run, the result you get should be similar to the results I listed. Next, you may write test code first, write work code, or opposite, write work code, and then write test code. I am more likely to use the former method: write test code first, write work code. Because this makes it clearly understand the behavior of work classes when writing work code.
Pay attention to writing a certain test code (such as the example in the article) does not make sense, only test code can help us find bugs, test code has its value. In addition, the test code should also test the work code. If the parameters called by the method are sent to the null value, the error value, and the correct value, see if the behavior of the method is as expected.
You now know the basic steps for writing test classes:
1> Expand TestCase class;
2> Override Runtest () method (optional);
3> Write some TestXxxxx () methods.
FixTure
The next question is that if you want to perform multiple tests for one or a number of classes, what should I do? JUnit has special solutions to this. If you need to perform multiple tests in one or a number of classes, these classes have become the test of the Context. In JUnit, it is called FixTure (like the Mycar and Expectedwheels in the TestCar class). When you write a test code, you will find that you spend a lot of time configuration / initialization related tests of FixTure. Putting the code for configuring fixture is not available in the construction of the test class, because we ask for multiple tests, I don't want the result of a test accident (if this is your request, then ) The results affecting other tests. Usually several tests use the same fixture, and each test has its own places that you need to change. To do this, Junit provides two ways to define in the TestCase class.
protected void setup () throws java.lang.exception
Protected void teardown () throws java.lang.exception
Overwrite Setup () methods, initialize all tests of FixTure (you can even create a network connection in Setup), which is slightly different from each test in the Testxxxx () method. Cover Teardown () (I always think of a guitar song called rain drops), release your permanent resources allocated in Setup (), such as database connections. When the JUnit performs a test, it calls setup () before performing each Testxxxxxx () method, and calls the Teardown () method after performing each Testxxxxxx () method, thereby ensuring that the test does not affect each other. Testcase
Need to be reminded that a considerable amount of Assert method is defined in the JUnit.framework.assert class, there are assert (), assertequals (), assertnull (), assertsame (), asserttrue (), fail (), etc. If you need to compare your own defined classes, such as Car. The Assert method requires you to override the Equals () method of the Object class to compare the difference between the two objects. Practice shows: If you override the equals () method of the Object class, it is best to override the HashCode () method of the Object class. Further, the toString () method of the Object class is also covered. This makes the test result more readable.
When you set fixture, the next step is to write the desired TestXxxx () method. Be sure to guarantee the PUBLIC property of the TestXxxx () method, otherwise the test cannot be called via the REFLECTION. Each extension TestCase class (that is, you have written test class) has multiple TestXxxx () methods. A TestXxx () method is a test. To run this test, you must define how to run the test. If you have multiple TestXxxx () methods, you have to define multiple times. JUnit supports two methods of running a single test: static and dynamic methods.
The static method is to cover the RUNTEST () method of the TestCase class, which is generally created by the internal class:
Testcase test01 = new testcar ("test getwheels")
{
Public void runtest ()
{
TestGetwheels ();
}
}
It is necessary to pay attention to each test with a static method (this name can be arbitrarily, but you must hope that this name has a meaning), so you can distinguish that test failed.
The dynamic method is to implement RUNTEST () to create a test instance with the internal province (Introspection, check the standard management component interface, and the process of designing design mode) to create a test instance. This requires the name of the test method that needs to be called:
Testcase Test01 = New Testcar ("TestGetWheels");
JUnit will dynamically find and call the specified test method. The dynamic method is very concise, but if you type the wrong name, you will get a strange NosuchMethodeXception exception. Dynamic methods and static methods are very good, you can choose according to your preferences. (Don't worry first, there is a more cool way to wait for you.)
Testsuite
Once you have created some test instances, the next step is to let them run together. We must define a TestSuite. In JUnit, this requires you to define a static suite () method in the TestCase class. The suite () method is like the Main () method, JUnit uses it to perform tests. In the suite () method, you add a test instance to a TestSuite object and return to this TestSuite object. A TestSuite object can run a set of tests. TestSuite and TestCase have implemented Test Interfaces, while the Test interface defines the methods required to run tests. This allows you to create a TestSuite with a combination of TestCase and TestSuite. That's why we say TestCase, TestSuite, and TestSuite have made composite pattern. The example is as follows: Public static test suite ()
{
Testsuite suite = new testsuite ();
Suite.Addtest (New Testcar ("TestGetWheels");
Suite.Addtest (New Testcar ("TestgetSeats");
Return suite;
}
Starting with JUnit 2.0, there is a simpler method for dynamically defining test instances. You only need to pass classes to TestSuite, and Junit automatically creates a corresponding test instance based on the test method name. So your test method is preferably named Testxxx (). The example is as follows:
Public Static Test Suite ()
{
Return New TestSuite (TestCar.class);
}
From JUnit's design, we can see that JUnit is not only available for unit testing, but also for integration testing. For integration tests with JUnit, please refer to the relevant information.
For compatibility, the following examples are listed in the following example:
Public Static Test Suite ()
{
Testsuite suite = new testsuite ();
Suite.addtest
New Testcar ("Car.Getwheels")
{
Protected void runtest ()
{
TestGetwheels ();
}
}
);
Return suite;
}
Testrunner
With TestSuite, we can run these tests, Junit provides three interfaces to run test
[Text Ui] junit.textui.teStrunner
[AWT UI] junit.awtui.teStrunner
[Swing ui] junit.swingui.teStrunner
We have already seen the text interface in front, let's take a look at the graphical interface:
The interface is simple, type the class name -TestCar. Or when you start the UI, type the class name:
[Windows] d: /> java junit.swingui.teestrunner testcar
[UNIX]% junit.swingui.teestrunner testcar
From the graphics UI, you can run the test to check the test results. There is also a problem. Need to note: If JUnit reports the test is not successful, Junit will distinguish between failures and errors. Failure is a result that is expected by the ASSERT method. The error is caused by an unexpected problem, such as ArrayIndexOutofboundSexception.
Since Testrunner is very simple, the interface is also intuitive, so there is not much introduction. Friends can refer to the relevant information. JUnit Best Practice
Martin Fowler said: "When you try to print some information or debug an expression, write some test code to replace those traditional methods." At the beginning, you will find that you always want you Create some new fixture, and test seem to make your programming speed slow down. Soon, you will find that you reuse the same fixture, and new tests usually only involve adding a new test method.
You may write a lot of test code, but you will soon find that the test you want to think is really useful. The test you need is the test that will fail, that is, those that you think will not fail, or you think that you should fail.
We mentioned earlier testing is a process that does not interrupt. Once you have a test, you have to keep it working properly to verify the new work code you join. Don't run test every few days or in the end, you should run test code every day. This kind of investment is small, but you can make sure you get a reliable work code. Your rework rate is low, you will have more time to write work code.
Don't think that the pressure is large, don't write the test code. On the contrary, write test code will gradually alleviate your pressure, and you should have an exact understanding of the behavior of the class by writing test code. You will write an efficient work code faster. Here are some specific methods or better practices for writing test code:
1. Do not initialize FixTure with the constructor of TestCase, and use setup () and teardown () methods;
2. Do not rely or assume the order of test run, because JUnit uses the Vector Save Test Method. So different platforms will take out test methods from VECTORs in different orders;
3. Avoid writing TestCase with side effects. For example: If the subsequent test depends on some specific transaction data, it is not necessary to submit transaction data. Simple rollback can be;
4. When inheriting a test class, remember to call the setup () and teardown () method of the parent class;
5. Place the test code and work code together, synchronize and update, while using the ANT to support JUnit's Task);
6. Test class and test methods should have a consistent naming scheme. If you add TEST in front of the work class to form a test class name;
7. Make sure the test is not related to time, do not rely on the use of expired data for testing. It is difficult to reproduce the test during subsequent maintenance;
8. If you write software to the international market, you should consider international factors when preparing tests. Don't test only with the mother language LOCALE;
9. Use the JUnit to provide an ASSERT / FAIL method and an abnormality process, which can make the code more concise;
10. Test should be as small as possible and perform fast.
In fact, JUnit can also be used to integrate testing, but I didn't involve it. There are two reasons: First, because there is no unit test, integration test is not talking. We are very difficult for us to accept the concept of testing, and if you introduce an integrated test, it will be more difficult. Second, I am more lazy, I hope to give the task of the integrated test to the test personnel. There are some related articles on JUnit's website, you can turn over.
JUnit and J2EE
If you carefully think about it, you will find that JUnit has its own limitations, such as testing of graphics interfaces, and testing for servlet / JSP, and EJBs. In fact, JUnit has a way to test for the GUI interface, servlet / jsp, javabean, and EJB. About the test of GUI is more complicated, suitable for introducing a whole article. Not much here. The test we did actually had an implicit environment, and the JVM our class needs this JVM to execute. In the J2EE framework, servlet / JSP, EJB requires its own operating environment: Web Container and EJB Container. Therefore, if you want to test the servlet / jsp, EJB, you need to deploy it in the corresponding Container to test. Since EJB does not involve UI issues (unless the EJB operation XML data, the test code at this time is more difficult to write, it is possible that you can compare whether the two DOM trees contain the same content) As long as the test code can be run, you can run the test code. At this point, the setup () method is particularly useful, and you can use JNDI to find specific EJBs in the Setup () method. In the TestXxx () method, the method of tested and tested these EJBs is called.
The JavaBean referred to here also does not have a problem with the UI, for example, we use JavaBean to access the database, or use JavaBean to package EJB. If such JavaBean does not use the service provided by Container, you can test directly, just like the general class of the general class mentioned earlier. If such JavaBean uses the service provided by Container, you need to deploy it in the Container to test. The method is similar to EJB. Testing for servlet / JSP is more difficult, it is recommended to construct httpRequest and httpresponse in the test code, and then compare, which requires developers to have a relatively deep understanding of the HTTP protocol and the internal implementation of the servlet / JSP. I think this is not realistic. Some people also propose using httpunit. Since I know much about CACTUS and HTTPUNIT, I can't make a suitable suggestion. I hope that the prophets can enlighten me.
It is precisely because JUnit's openness and simple and easy, this introduction article will be introduced. But technology is always updated, and I have not understood testing; I can simplify a complex concept into a very easy to understand. But my original intention only hopes to reduce the threshold for developers to step into the test field, not to modify or redefine some concepts. This is especially necessary to emphasize. Finally, if some brothers and sisters give me some precautions or I will be very grateful for me to understand some problems.
reference
JUnit implementation
Author: eric site: http: //www.neweasier.com/article/2002-08-07/1028723459.html
How to use JUnit Framework to write unit testing
Author: cinc site: http: //www.chinaunix.net/bbsjh/14/546.html
It is mainly to reference CINC's comments. As for Mr. Shen Wenbo's "How to use JUnit Framework for unit testing" original text I suggest that everyone has time to look at it, write very well, I have not integrated here.
Create a JUnit test case
Author: BUILDER.COM site: http: //www.zdnet.com.cn/developer/code/story/0,2000081534,39033729,00.htm