Table of Contents LESSON: The JUnit Test Tool...1 Subjects...2 Testing 123...3 What JUnit Provides...4 JUnit Concepts...5 Example Testing a Queue Class...6 Example TestCase Class for Queue...7 Example Running the Test using GUI...9 Example Running the Test (Fail)...10 Example Combining Tests into a TestSuite...11 Multiple Ways to Run Tests...12 TestCase...13 TestSuite...14 TestRunners...15 TestResult...16 Invokation and Reporting with Ant...17 Example Invokation with Ant...18 Example Invokation and Reporting with Ant...19 LABS...19 1. Installing JUnit...19 2. Creating and Running a TestCase...19 RESOURCES...21 i
LESSON: The JUnit Test Tool author: Just van den Broecke just@justobjects.nl organization: Just Objects www.justobjects.nl Slides Labs 1. Subjects 2. Testing 123 3. What JUnit Provides 4. JUnit Concepts 5. Example Testing a Queue Class 6. Example TestCase Class for Queue 7. Example Running the Test using GUI 8. Example Running the Test (Fail) 9. Example Combining Tests into a TestSuite 10. Multiple Ways to Run Tests 11. TestCase 12. TestSuite 13. TestRunners 14. TestResult 15. Invokation and Reporting with Ant 16. Example Invokation with Ant 17. Example Invokation and Reporting with Ant 1. Installing JUnit 2. Creating and Running a TestCase Resources 1
Subjects Testing Features Framework Examples JUnit with Ant The JUnit Test Tool 1 JUnit is a regression testing framework written by Erich Gamma and Kent Beck. It is used by the developer who implements unit tests in Java. JUnit is Open Source Software, released under the IBM's Common Public License Version 0.5 and hosted on SourceForge. 2
Testing 123 We all agree that testing is important. Depending on your project some or all of these test types are relevant. White box testing (a.k.a developer/unit testing) Black box testing (system as a whole) Stress testing Performance testing User experience testing Etc Develop your testing strategy upfront! The JUnit Test Tool 2 3
What JUnit Provides Facilitate creating tests for Java code primarily white box (unit) testing entire test cycle: setup/run/evaluate/teardown/report bundling large numbers of tests (suites) "test first" strategy for extreme Programming Clean separation of application code and test code IDE integration (JBuilder, VA, IntelliJ,..) Easy automation and reporting with Ant An extensible open source framework lightweight: few concepts and key classes versatile: possibility to extend for your testing needs Download and info on www.junit.org The JUnit Test Tool 3 4
JUnit Concepts JUnit is a lightweight framework with only a few key classes TestCase subclass contains your tests TestSuite a composite of TestCases and/or TestSuites TestRunners to run TestCases or TestSuites TestResult collects results of multiple tests Tip: JUnit comes with sources (src.jar). Worthwhile to study The JUnit Test Tool 4 5
Example Testing a Queue Class 1: /** 2: * FIFO Queue implemented through circular array. 3: * 4: * @version $Id: Queue.java,v 1.2 2004/03/14 15:43:01 justb Exp $ 5: */ 6: public class Queue { 7: 8: public Queue(int acapacity) { 9: capacity = acapacity; 10: queue = new Object[capacity]; 11: } 12: 13: public boolean enqueue(object anitem) { 14: if (count == capacity) { 15: return false; 16: } 17: 18: queue[last] = anitem; 19: last = next(last); 20: count++; 21: return true; 22: } 23: 24: public Object dequeue() { 25: if (count == 0) { 26: return null; 27: } 28: 29: Object frontitem = queue[first]; 30: queue[first] = null; 31: count ; 32: first = next(first); 33: return frontitem; 34: } 35: 36: private int next(int index) { 37: return (index + 1) % capacity; 38: } 39: 40: private int count; 41: private int capacity; 42: private Object[] queue; 43: private int first, last; 44: } The JUnit Test Tool 5 JUnit proved its value once more: I was using this Queue class for years but still one of the tests (queue full) failed when the Queue was at capacity 1! A minor bug was still present in a previous version. 6
Example TestCase Class for Queue 1: 2: import junit.framework.testcase; 3: 4: /** 5: * JUnit test case of FIFO Queue. 6: * 7: * @version $Id: QueueTest.java,v 1.4 2004/03/14 15:43:01 justb Exp $ 8: */ 9: public class QueueTest extends TestCase { 10: 11: public QueueTest(String aname) { 12: super(aname); 13: } 14: 15: protected void setup() { 16: queue3 = new Queue(3); 17: queue4 = new Queue(4); 18: } 19: 20: protected void teardown() { 21: queue3 = null; 22: queue4 = null; 23: } 24: 25: public void testfifo() { 26: queue4.enqueue("just"); 27: queue4.enqueue("dave Dee"); 28: queue4.enqueue("dozy"); 29: queue4.enqueue("beaky"); 30: assertequals(queue4.dequeue(), "Dave Dee"); 31: assertequals(queue4.dequeue(), "Dozy"); 32: assertequals(queue4.dequeue(), "Beaky"); 33: } 34: 35: public void testqueuefull() { 36: queue4.enqueue("dave Dee"); 37: queue4.enqueue("dozy"); 38: queue4.enqueue("beaky"); 39: queue4.enqueue("mick"); 40: asserttrue("queue Full",!queue4.enQueue("Tich")); 41: } 42: 43: public void testqueueempty() { 44: assertnull(queue3.dequeue()); 45: 46: queue3.enqueue("dave Dee"); 47: queue3.enqueue("dozy"); 48: queue3.enqueue("beaky"); 49: queue3.dequeue(); 50: queue3.dequeue(); 51: queue3.dequeue(); 52: assertnull("queue Empty", queue3.dequeue()); 53: } 54: 55: public static void main(string[] args) { 56: // Runs an entire TestSuite using Swing UI 57: junit.swingui.testrunner.run(queuetest.class); 58: } 59: 60: private Queue queue3; 61: private Queue queue4; 62: } The JUnit Test Tool 6 7
8
Example Running the Test using GUI The JUnit Test Tool 7 9
Example Running the Test (Fail) The JUnit Test Tool 8 10
Example Combining Tests into a TestSuite 1: import junit.framework.*; 2: 3: /** 4: * TestSuite examples. 5: * 6: * @version $Id: SuiteTest.java,v 1.3 2004/03/14 15:43:01 justb Exp $ 7: */ 8: public class SuiteTest { 9: 10: public static void main(string[] args) { 11: // Runs an entire TestSuite using text UI 12: junit.textui.testrunner.run(suite()); 13: } 14: 15: public static Test suite() { 16: TestSuite suite = new TestSuite("All Tests"); 17: 18: // Use introspection. 19: suite.addtest(new TestSuite(QueueTest.class)); 20: 21: // The above is equivalent to: 22: // suite.addtest(new QueueTest("testFIFO")); 23: // suite.addtest(new QueueTest("testQueueFull")); 24: // suite.addtest(new QueueTest("testQueueEmpty")); 25: 26: // add more TestSuites/TestCases, for example 27: // suite.addtest(new TestSuite(StackTest.class)); 28: 29: return suite; 30: } 31: } The JUnit Test Tool 9 11
Multiple Ways to Run Tests 1: import junit.framework.*; 2: 3: /** 4: * Shows multiple ways to run JUnit tests. 5: * 6: * @version $Id: RunTest.java,v 1.2 2004/03/14 15:43:01 justb Exp $ 7: */ 8: public class RunTest { 9: 10: public static void showresult(string amessage, TestResult atestresult) { 11: System.out.println("RESULTS FOR " + amessage); 12: System.out.println("tests run=" + atestresult.runcount()); 13: System.out.println("failures=" + atestresult.failurecount()); 14: System.out.println("errors=" + atestresult.errorcount() + "\n"); 15: } 16: 17: public static void main(string[] args) { 18: TestResult testresult; 19: TestSuite testsuite; 20: 21: // 1. Run a single Test from the TestCase 22: testresult = new TestResult(); 23: new QueueTest("testFIFO").run(testResult); 24: showresult("testcase single Test", testresult); 25: 26: // 2. Run two Tests from the TestCase using TestSuite 27: testresult = new TestResult(); 28: testsuite = new TestSuite(); 29: testsuite.addtest(new QueueTest("testQueueFull")); 30: testsuite.addtest(new QueueTest("testQueueEmpty")); 31: testsuite.run(testresult); 32: showresult("testsuite 2 tests", testresult); 33: 34: // 3. Run all Tests from the TestCase using TestSuite 35: testresult = new TestResult(); 36: testsuite = new TestSuite(QueueTest.class); 37: testsuite.run(testresult); 38: showresult("testsuite all tests", testresult); 39: 40: // 4. Do the same as 1 3 but using TestRunner (text UI) 41: junit.textui.testrunner.run(new QueueTest("testFIFO")); // as 1. 42: 43: testsuite = new TestSuite(); 44: testsuite.addtest(new QueueTest("testQueueFull")); 45: testsuite.addtest(new QueueTest("testQueueEmpty")); 46: junit.textui.testrunner.run(testsuite); // as 2. 47: 48: junit.textui.testrunner.run(queuetest.class); // as 3. 49: junit.textui.testrunner.run(new TestSuite(QueueTest.class)); // as 3. (alt.) 50: } 51: } The JUnit Test Tool 10 12
TestCase junit.framework.testcase Your test class should subclass TestCase Tests are implemented as methods of TestCase Test methods must start with test e.g. testqueuefull() Fixtures: use method setup() to create preconditions for each test Asserts: use methods assert*() to verify the test outcomes Cleanup: use method teardown() to cleanup after each test The JUnit Test Tool 11 13
TestSuite junit.framework.testsuite Composite of TestCase and TestSuite objects Allows you to run multiple tests and collect results The JUnit Test Tool 12 14
TestRunners Allow you to run TestCases or TestSuites. Two flavours Textual TestRunner console mode example: junit.textui.testrunner.run(queuetest.class) Graphical TestRunners Swing or AWT simple graphical dialog to enter the testcases/suites provide some graphical progress indication example: junit.swingui.testrunner.run(mytestsuite.class) The JUnit Test Tool 13 A TestRunner can be configured to be either loading or non loading. In the loading configuration the TestRunner reloads your class from the class path for each run. As a consequence you don't have to restart the TestRunner after you have changed your code. In the non loading configuration you have to restart the TestRunner after each run. The TestRunner configuration can be either set on the command line with the noloading switch or in the junit.properties file located in the "user.home" by adding an entry loading=false. Notice: don't use the loading behaviour when you are testing code that exercise JNI calls. The loading behaviour can be further configured with the excluded.properties file. In this file you can configure the list of package paths that should be excluded from loading. The loading of these packages is delegated to the system class loader. They will be shared across test runs. The excluded.properties file is located at in the junit.jar file and can be overridden by adding an excluded.properties file infront of the junit.jar file. 15
TestResult junit.framework.testresult Basically a data structure to collect outcomes from tests Each test outcome is success failure functional (assertion) failure error usually an uncaught Exception thrown by test method TestListeners allow for making extensions like formatters (see Ant) The JUnit Test Tool 14 16
Invokation and Reporting with Ant Ant includes two optional tasks for JUnit JUnit task runs TestCases/TestSuites and captures results results may be in several formats: text, XML run one TestCase or all test classes through pattern matching JunitReport task merges the individual XML files generated by the JUnit task applies XSL stylesheet on the resulting merged document to provide a browsable report of the testcases results Many advantages in the combination JUnit/Ant easy invokation combine nightly builds with nightly tests distribute build/test results by email publish HTML test reports on your intranet The JUnit Test Tool 15 17
Example Invokation with Ant 1: <! Some examples for JUnit tasks within Ant (see also Ant user manual) > 2: 3: <! Runs the test defined in my.test.testcase in the same VM. 4: No output will be generated unless the test fails. > 5: <junit> 6: <test name="my.test.testcase" /> 7: </junit> 8: 9: <! Runs the test defined in my.test.testcase in a separate VM. At 10: the end of the test a single line summary will be printed. 11: A detailed report of the test can be found in 12: TEST my.test.testcase.txt. The build process will be stopped if the 13: test fails. > 14: <junit printsummary="yes" fork="yes" haltonfailure="yes"> 15: <formatter type="plain" /> 16: <test name="my.test.testcase" /> 17: </junit> 18: 19: <! Extended example. > 20: <junit printsummary="yes" haltonfailure="yes"> 21: <classpath> 22: <pathelement location="${build.tests}" /> 23: <pathelement path="${java.class.path}" /> 24: </classpath> 25: 26: <formatter type="plain" /> 27: 28: <! Runs my.test.testcase in the same VM (ignoring the given CLASSPATH), only a 29: warning is printed if this test fails. In addition to the plain text test results, 30: for this test a XML result will be output to result.xml. > 31: <test name="my.test.testcase" haltonfailure="no" outfile="result" > 32: <formatter type="xml" /> 33: </test> 34: 35: <! For each matching file in the directory ${src.tests} a test is run in a separate VM. 36: If a test fails, the build process is aborted. Results are collected in files named TEST name.txt 37: and written to ${reports.tests}. > 38: <batchtest fork="yes" todir="${reports.tests}"> 39: <fileset dir="${src.tests}"> 40: <include name="**/*test*.java" /> 41: <exclude name="**/alltests.java" /> 42: </fileset> 43: </batchtest> 44: </junit> 45: The JUnit Test Tool 16 18
Example Invokation and Reporting with Ant 1: <! All in one: target that performs all tests and produces HTML results > 2: <target name="test" depends="compile"> 3: 4: <junit printsummary="yes" haltonfailure="no" fork="no" dir="${base}"> 5: 6: <formatter type="xml" usefile="yes" /> 7: 8: <batchtest todir="${base}/test/report"> 9: <fileset id="junit.all.fileset" dir="${base}/test/src" > 10: <include name="**/test*.java" /> 11: </fileset> 12: </batchtest> 13: 14: </junit> 15: 16: <junitreport todir="${base}/test/report"> 17: 18: <fileset dir="${base}/test/report"> 19: <include name="test *.xml"/> 20: </fileset> 21: 22: <report format="frames" todir="${base}/test/report"/> 23: 24: </junitreport> 25: 26: </target> The JUnit Test Tool 17 LABS 1. Installing JUnit In this lab you will install JUnit from the download file. 1. Get junitx.y.zip (e.g. junit3.7.zip) and unpack 2. Add junit.jar to the CLASSPATH. For example: set classpath=%classpath%;install_dir\junit3.7\junit.jar 3. Test the installation by using either the batch or the graphical TestRunner tool to run the tests that come with the release. All the tests should pass OK. Notice: that the tests are not contained in the junit.jar but in the installation directory directly (see INSTALL_DIR/junit/). Therefore make sure that the installation directory is on the classpath For the batch TestRunner type: java junit.textui.testrunner junit.samples.alltests For the graphical TestRunner type: java junit.awtui.testrunner junit.samples.alltests For the Swing based graphical TestRunner type:: java junit.swingui.testrunner junit.samples.alltests 2. Creating and Running a TestCase In this lab you will create and run tests. It is also a drill to get into to the extreme Programming (XP) discipline to write tests before doing implementation! 19
1. We will create a class Stack similar to the Queue example in the lesson. A skeleton of the code is provided here: 1: /** 2: * LIFO Stack implemented through array. 3: * 4: * @version $Id: Stack.java,v 1.2 2004/03/14 15:43:01 justb Exp $ 5: */ 6: public class Stack { 7: 8: public Stack(int acapacity) { 9: // YOUR CODE HERE 10: } 11: 12: public boolean put(object anitem) { 13: // YOUR CODE HERE 14: return false; 15: } 16: 17: public Object take() { 18: // YOUR CODE HERE 19: return null; 20: } 21: 22: private Object[] stack; 23: } 2. Think of what you want to test for the Stack, in particular boundaries (empty/full) 3. Create a subclass of TestCase where you implement your tests 4. Implement the tests first 5. Try different ways to run the tests: directly and using the TestRunners. (All tests should fail as expected). 6. Now implement the Stack. If your progress is ok, your failed tests should become successful. 7. Refactoring: change the Stack implementation by using a java.util.vector (or your own linked list) and get the tests running again. 20
RESOURCES [junit 1] [junit 2] [ibm 1] JUnit.org ; JUnit, Testing Resources for Extreme Programming ; This site is dedicated to software developers using JUnit or one of the other XUnit testing frameworks. We'll be adding more content and web based services over time. Initially we'll be providing links to give you a one stop destination to learn the latest information on unit testing. http://www.junit.org JUnit.org ; JUnit SourceForge Project ; JUnit is a simple framework to write repeatable tests. It is an instance of the xunit architecture for unit testing frameworks. http://junit.sourceforge.net Malcolm Davis (malcolm@nuearth.com) ; Incremental development with Ant and JUnit ; Using unit test to improve your code in small steps. A small change in your software development habits can have a huge payoff in the quality of your software. Incorporate unit testing into your development process and see how much time and effort you save in the long run. This article explores the benefits of unit testing, in particular using Ant and JUnit, with code samples. http://www 106.ibm.com/developerworks/library/j ant/?dwzone=java 21