!---------------------------------------------! ! Unit Testing Guide ! ! ! ! to run the tests: 'ant testall' ! !---------------------------------------------! 1. What is unit testing? Writing code that will check whether a small unit of code works is called unit testing. Example: If we encode directions like this protected static final int N = 0, NE = 1, E = 2, SE = 3, S = 4, SW = 5, W = 6, NW = 7; and we want to write a function that returns the opposite direction. Usually we would write the implementation public static int getOppositeDirection(int direction) { return (direction < 4) ? direction + 4 : direction - 4; } and then manually check that the method works correctly by either testing the compiled code within the application itself (in FreeCol this would mean verifying that each direction is properly made opposite via the GUI output) or for a console-based application performing a series of calls to the System.out.println function to output whether or not each case worked properly. Instead we can write source code that verifies whether the function behaves correctly: public void testGetOppositeDirection() throws FreeColException { assertEquals(Map.S, Map.getOppositeDirection(Map.N)); assertEquals(Map.N, Map.getOppositeDirection(Map.S)); assertEquals(Map.E, Map.getOppositeDirection(Map.W)); assertEquals(Map.W, Map.getOppositeDirection(Map.E)); assertEquals(Map.NE, Map.getOppositeDirection(Map.SW)); assertEquals(Map.NW, Map.getOppositeDirection(Map.SE)); assertEquals(Map.SW, Map.getOppositeDirection(Map.NE)); assertEquals(Map.SE, Map.getOppositeDirection(Map.NW)); } Each assert statement will check whether the given condition holds true. If all assert statements succeed, the test passes (this may be indicated by a green bar in some IDEs) otherwise the test fails (this may be indicated with a red bar), telling you which line did not pass the assertion. 2. Why write tests? * Verify that code works as expected in certain situations. * To describe a bug to other developers, a test which fails can be cited as an example. 3. What are the benefits? * Be able to run all the tests after a change to see if one broke existing functionality ("regression test"), thus after enough tests have been written, it is easier to be confident about changing the code. * A test describes what a piece of code is supposed to do and often can help to understand how it is supposed to be used. * Since the test is written in source code it is much faster to run than manual tests in the application. 4. Drawbacks? * Writing test cases can be a lot of work. * Testing of GUIs is especially difficult. * One needs a lot of tests to get benefits like the regression checking. 5. How do I write test cases? * Create a new class in the test/src folder that extends the class TestCase (import org.junit.*). All methods in this class that have a name that starts in "test...." will be executed. * To check basic conditions use assertEquals, assertTrue, assertFalse, assertNotNull, etc... * To check for exceptions to occur use the following construction: try { // code that should throw exception ... fail() } catch (FreeColException e){ // Exception throws, thus okay } * To fail if an exception is thrown, just declare it: public void testGetOppositeDirection() throws FreeColException { 6. How to run a test case? a.) In Eclipse to run a test case: Right click the Test class -> Run As... -> JUnit Test b.) On the command line the main directory (replace the text between $ $): java -cp $classpath for the class files from both src/ and test/src$;test/lib/junit.jar junit.swingui.TestRunnerorg $fully qualified name of the test class$ For instance if bin is your target directory and you want to run all tests java -cp bin;test/lib/junit.jar junit.swingui.TestRunner net.sf.freecol.AllTests c.) Using ant run: If you have Apache Ant 1.7 or higher you can just run ant testall Otherwise: ant -lib test/lib/junit.jar -Dtest=$qualified name of test class but ommitting net.sf.freecol$ test for instance ant -lib test/lib/junit.jar -Dtest=AllTests test 7. FAQ Q: What is the difference between unit and integration testing? A: In unit testing the goal is to test small units in relative isolation, while integration testing tries to figure out whether parts of the system work if put together. Both approaches have their purpose and their strengths. In general one should try to first test code that has little dependencies to other code or remove the dependencies by using mock objects and later see whether the code integrates with the rest of the system. 8. References: [1] JUnit Test Infected: Programmers Love Writing Tests http://junit.sourceforge.net/doc/testinfected/testing.htm [2] JUnit Homepage http://junit.org