5.1. Using JUnit JUnit is an open source testing framework housed online at http://www.junit.org/, where you'll find downloads and documentation. Using JUnit, you can construct a set of standard tests for everyone working on an application, and if they change the application's code, all they'll need is to run the build file to verify that the application still passes the standard set of tests. JUnit is primarily made up of a set of assertion methods that can test various conditions. Here they are:
- assertEquals(a, b)
-
Tests if a is equal to b (a and b are primitive values or must have an equals method for comparison purposes)
- assertFalse(a)
-
Tests if a is false, where a is a boolean value
- assertNotNull(a)
-
Tests if a is not null, where a is an object or null
- assertNotSame(a, b)
-
Tests if a and b do not refer to the identical object
- assertNull(a)
-
Tests if a is null, where a is an object or null
- assertSame(a, b)
-
Tests if a and b refer to the identical object
- assertTrue(a)
-
Tests if a is frue, where a is a boolean value To work with JUnit, you modify your code to extend the junit.framework.TestCase class, which in turn extends the junit.framework.Assert class. After subclassing the TestCase class, you can use the various assertXXX( ) methods to test the results from your newly compiled code. Each of these methods, along with their various versions, are listed in Table 5-1. | Though your code extends the TestCase class, these methods are part of TestCase's base class, the Assert class. |
|
Table 5-1. The junit.framework.Assert methods Method | Does this |
---|
static void assertEquals(boolean expected, boolean actual) | Tests if two booleans are equal | static void assertEquals(byte expected, byte actual) | Tests if two bytes are equal | static void assertEquals(char expected, char actual) | Tests if two chars are equal | static void assertEquals(double expected, double actual, double delta) | Tests if two doubles are equal within a value named delta | static void assertEquals(float expected, float actual, float delta) | Tests if two floats are equal within a value named delta | static void assertEquals(int expected, int actual) | Tests if two ints are equal | static void assertEquals(long expected, long actual) | Tests if two longs are equal | static void assertEquals(java.lang.Object expected, java.lang.Object actual) | Tests if two objects are equal | static void assertEquals(short expected, short actual) | Tests if two shorts are equal | static void assertEquals(java.lang.String message, boolean expected, boolean actual) | Tests if two booleans are equal | static void assertEquals(java.lang.String message, byte expected, byte actual) | Tests if two bytes are equal | static void assertEquals(java.lang.String message, char expected, char actual) | Tests if two chars are equal | static void assertEquals(java.lang.String message, double expected, double actual, double delta) | Tests if two doubles are equal within a value given by delta | static void assertEquals(java.lang.String message, float expected, float actual, float delta) | Tests if two floats are equal within a value given by delta | static void assertEquals(java.lang.String message, int expected, int actual) | Tests if two ints are equal | static void assertEquals(java.lang.String message, long expected, long actual) | Tests if two longs are equal | static void assertEquals(java.lang.String message, java.lang.Object expected, java.lang.Object actual) | Tests if two objects are equal | static void assertEquals(java.lang.String message, short expected, short actual) | Tests if two shorts are equal | static void assertEquals(java.lang.String expected, java.lang.String actual) | Tests if two Strings are equal | static void assertEquals(java.lang.String message, java.lang.String expected, java.lang.String actual) | Tests if two Strings are equal | static void assertFalse(boolean condition) | Tests if a condition is false | static void assertFalse(java.lang.String message, boolean condition) | Tests if a condition is false | static void assertNotNull(java.lang.Object object) | Tests if an object isn't null | static void assertNotNull(java.lang.String message, java.lang.Object object) | Tests if an object isn't null | static void assertNotSame(java.lang.Object expected, java.lang.Object actual) | Tests if two objects do not refer to the same object | static void assertNotSame(java.lang.String message, java.lang.Object expected, java.lang.Object actual) | Tests if two objects do not refer to the same object | static void assertNull(java.lang.Object object) | Tests if an object is null | static void assertNull(java.lang.String message, java.lang.Object object) | Tests if an object is null | static void assertSame(java.lang.Object expected, java.lang.Object actual) | Tests if two objects refer to the same object | static void assertSame(java.lang.String message, java.lang.Object expected, java.lang.Object actual) | Tests if two objects refer to the same object | static void assertTrue(boolean condition) | Tests if a condition is true | static void assertTrue(java.lang.String message, boolean condition) | Tests if a condition is true | static void fail( ) | Makes a test fail | static void fail(java.lang.String message) | Makes a test fail with the specified message |
Table 5-2 lists the methods specific to the JUnit TestCase method. Table 5-2. The junit.framework.TestCase methods Method | Does this |
---|
int countTestCases( ) | Counts how many test cases are executed | protected TestResult createResult( ) | Creates a default TestResult object | java.lang.String getName( ) | Gets the name of a TestCase and returns it | TestResult run( ) | Runs a test, storing results in a TestResult object | void run(TestResult result) | Runs a test case and stores the results in TestResult | void runBare( ) | Executes a bare test | void setName(java.lang.String name) | Specifies the name of a test case | protected void setUp( ) | Lets you perform initialization operations | protected void tearDown( ) | Lets you clean up after your tests, such as closing a network connection | java.lang.String toString( ) | Returns a string representation of a case |
5.1.1. Writing the Tests To add JUnit test cases to your code, you import junit.framework.TestCase, base your application's class on it, and write test cases. Test cases are methods whose name begins with "test", which means JUnit will call them automatically. In this example, there are three test cases: testTrue( ) to test the return value of the returnTrue( ) method, testEquals( ) to test the results of the return4( ) method, and testNotNull( ) to test the results of the returnObject( ) method. All three of these test cases will be called automatically by the JUnit framework. Inside test cases, you can use the JUnit methods like assertTrue( ), assertEquals( ), and so on, to make sure the build didn't break your application. To make this work, import junit.framework.TestCase, extend that class, and add three test cases to test the three methods in your codehe JUnit framework will call all three test cases automatically because their names start with "test": package org.antbook; import junit.framework.TestCase; public class Project extends TestCase { public Project (String name) { } public void testTrue( ) { . . . } public void testEquals( ) { . . . } public void testNotNull( ) { . . . } public boolean returnTrue( ) { return true; } public int return4( ) { return 2 + 2; } public Object returnObject( ) { return new Integer(1); } public static void main(String args[]) { Project project = new Project("project"); System.out.println(project.returnTrue( )); System.out.println(project.return4( )); System.out.println(project.returnObject( )); } } Use the JUnit methods assertTrue( ), assertEquals( ), and assertNotNull( ) to test the results from the three methods in Project.javafor example, testing if the return value of return4 really is 4, as it should be. If any of these assertions don't work, an exception is thrown, and that exception causes the build to fail: package org.antbook; import junit.framework.TestCase; public class Project extends TestCase { public Project (String name) { } public void testTrue( ) { assertTrue("assertTrue test", returnTrue( )); } public void testEquals( ) { assertEquals("assertEquals test", 4, return4( )); } public void testNotNull( ) { assertNotNull("assertNotNull test", returnObject( )); } public boolean returnTrue( ) { return true; } public int return4( ) { return 2 + 2; } public Object returnObject( ) { return new Integer(1); } public static void main(String args[]) { Project project = new Project("project"); System.out.println(project.returnTrue( )); System.out.println(project.return4( )); System.out.println(project.returnObject( )); } } Besides writing test cases like these, you can add two additional methods, setUp( ) and tearDown( ), to your code. These methods act much like constructors and destructors for your tests:
- protected void setUp( )
-
Lets you perform initialization, for example, opening a network connection
- protected void tearDown( )
-
Lets you clean up after the tests are completefor example, closing a network connection | For further details on how JUnit works, see the JUnit site at http://www.junit.org/index.htm. |
|
5.1.2. Performing Tests with the junit Task The Ant junit task lets you run JUnit tests from Ant. It's an optional task, so you'll need need to install junit.jarwhich you get from http://www.junit.org/æin the Ant lib directory. Using junit, you can tell Ant which .class files you want tested, and JUnit will run the test cases in those files. The attributes of the junit task appear in Table 5-3. Table 5-3. The junit attributes Attribute | Description | Required | Default |
---|
dir | Specifies the directory where you want to run the JVM. Ignored if fork is disabled. | No | | errorproperty | Specifies the name of a property you want set in case there was an error. | No | | failureproperty | Specifies the name of a property in case the task failed. | No | | filtertrace | Removes Junit and Ant stack frames from error stack traces. | No | on | fork | Specifies that you want to run tests in a new JVM. | No | off | haltonerror | Specifies you want to stop the build if there are errors. | No | off | haltonfailure | Specifies you want to stop the build if the test fails. | No | off | includeantruntime | Specifies you want to add the Ant classes and JUnit to the classpath in a forked JVM. | No | true | jvm | Specifies the command used to start the Java Virtual Machine. Ignored if fork is disabled. | No | "java" | maxmemory | Specifies the maximum amount of memory to give to the forked JVM. Ignored if fork is disabled. | No | | newenvironment | Specifies you don't want to copy the old environment when new environment variables are specified. Ignored if fork is disabled. | No | false | printsummary | Specifies you want statistics for each test case. Possible values: on, off, and withOutAndErr (which is the same as on but also writes output of the test as written to System.out and System.err). | No | off | reloading | Specifies whether you want a new classloader to be started for each test case. Since Ant 1.6. | No | TRue | showoutput | Sends any output to Ant's logging system and to the formatters you specify. | No | Only the formatters receive the output. | tempdir | Specifies where you want this task to place temporary files. Since Ant 1.6. | No | The project's base directory. | timeout | Specifies you want to stop a test if it doesn't finish in time. Time is measured in milliseconds. Ignored if fork is disabled. | No | |
The junit task supports a nested classpath element that represents a path-like structure, and which you can use to set the classpath used while the tests are running. A number of other elements may be nested inside the junit element. If you're using fork, you can pass additional parameters to the new JVM with nested jvmarg elements: <junit fork="yes"> <jvmarg value="-Djava.compiler=NONE"/> . . . </junit> | You can specify environment variables to pass to a forked JVM with nested env elements. I'll look at this element, including its attributes, in Chapter 7. |
|
Nested sysproperty elements can specify system properties required by the class you're testing. These properties will be made available to the JVM during the execution of the test. You can use the same attributes as the env task here; for example, you can use the key and value attributes to specifies properties and property values, as in this example: <junit> <sysproperty key="basedir" value="${basedir}"/> . . . </junit> 5.1.2.1 Formatting test results Test results can be printed in various formats, and you use the formatter nested element to specify which format to use (by default, the output of the tests will be sent to a file unless you set the usefile attribute to false). There are three predefined formatters: The XML formatter prints the test results in XML format. The plain formatter prints plain text. The brief formatter will give only brief details, only printing in-depth information for test cases that failed. I'll look at formatting the results of JUnit tests using these formatters in this chapter. The attributes of the formatter element appear in Table 5-4. Table 5-4. The formatter task's Attributes Attribute | Description | Required | Default |
---|
classname | Specifies the name of the custom formatter class you want to use. | Exactly one of type or classname. | | extension | Specifies the extension for the output filename. | Yes, if classname has been used. | | if | Specifies JUnit will only use this formatter if a specified property is set. | No | TRue | type | Specifies a predefined formatter you want to use. Possible values: xml, plain, or brief. | Exactly one of type or classname. | | unless | Specifies JUnit should use the formatter if a specified property is not set. | No | true | usefile | Specifies if you want to send output to a file. | No | true |
5.1.2.2 Specifying the test class You use the test nested element to specify a class to test. The attributes of this element appear in Table 5-5. Table 5-5. The test task's Attributes Attribute | Description | Required | Default |
---|
errorproperty | Specifies the the name of a property you want to have set if there is an error | No | | failureproperty | Specifies the name of a property in case the task fails | No | | filtertrace | Removes Junit and Ant stack frames from error stack traces | No | on | fork | Specifies you want to run tests in a new JVM | No | | haltonerror | Specifies you want to stop the build if there are errors | No | | haltonfailure | Specifies you want to stop the build if the test fails | No | | If | Specifies this test should run only if a specified property is set | No | | name | Specifies the name of the test class you want to use | Yes | | outfile | Sets the filename where the test results should go | No | TEST-name, where name is the name of the test specified in the name attribute | todir | Specifies the directory you want the reports written to | No | The current directory | unless | Specifies this test should run only if a specified property is not set | No | |
5.1.2.3 Running tests in batches Another nested element, batchtest, lets you set up a number of tests at once. The batchtest element collects the included files from any number of nested filesets, and generates a test class name for each file that ends in .java or .class. You'll use this element later in this chapter. The attributes for batchtest appear in Table 5-6. Table 5-6. The batchtest element's attributes Attribute | Description | Required | Default |
---|
errorproperty | Specifies the name of a property you want set in case there is an error | No | | failureproperty | Specifies the name of a property in case the task fails | No | | filtertrace | Removes Junit and Ant stack frames from error stack traces | No | on | fork | Specifies you want to run tests in a new JVM | No | | haltonerror | Specifies you want to stop the build if there are errors | No | | haltonfailure | Specifies you want to stop the build if the test fails | No | | if | Specifies this test should run only if a specified property is set | No | | todir | Specifies the directory where you want reports written to | No | The current directory | unless | Specifies this test should run only if a specified property is not set | No | |
Other nested elements are available since Ant 1.6. You can specify a set of properties to be used as system properties with syspropertysets. If you're forking a new JVM, you can specify the location of bootstrap class files using the bootclasspath path-like structure inside the junit task. You can revoke or grant security permissions during the execution of a class with a nested permissions element. And you can even control Java 1.4 assertions with an assertions subelement. |