ArgoUML has a set of automatic test cases using JUnit-framework for testing the insides of the code. The purpose of these are to help in pin-pointing problems with code changes before even starting ArgoUML.
The JUnit test cases are residing in a separate directory and
run from ant targets in the
src_new/build.xml
.
They are never distributed with ArgoUML but merely a tool for
developers.
By running the command
build tests guitests
in src_new
these test cases are started, each in their own jvm.
Each test case writes its result on the Ant log.
The result is also generated into a set of files that can be found at
build/test/reports/junit/output/html/index.html
.
The test cases' java source code is located under
argouml/tests/org/argouml
.
Now this will make all you java-enthusiasts go nuts! We have both class names and method names with a special syntax.
The name of the test case class starts with "Test" (i.e. Capital T, then
small e, s and t) or
"GUITest" (i.e. Capital G, U, I, T then small e, s, t).
The reason for this is that the special targets in
src_new/build.xml
search for test case classes with these names.
If you write a test case class that does not comply to this rule, you still
can run the test cases in this class manually
by starting with
build run-with-test-panel,
but it wont be known and run by other developers and automatic build
mechanisms so don't do it.
Test case classes that don't require GUI components in place
have filenames like
Test
.
They must be able to run on a headless system.
To make sure that this works, always run your newly developed
test cases with build tests using
jdk1.4 or later.
*
.java
Test case classes that do require GUI components in place
have filenames like
GUITest
.
*
.java
We should try to get as many tests from a GUITest* class to the corresponding Test* class because the latter are run by automatic builds regularly.
Every class
org.argouml.
stored in the file
x.y
.z
src_new/org/argouml/
should have a JUnit test case class called
x/y
/z
.javaorg.argouml.
stored in the file
x.y
.Testz
tests/org/argouml/
containing all the Unit Test Cases for that class
that don't need the GUI components to run.
Tests that
do need GUI components to run should be part of a class named
x/y
/Testz
.javaorg.argouml.
stored in the file
x.y
.GUITestz
tests/org/argouml/
x/y
/GUITestz
.java
If you only want to run your newly written test cases and not
all the test cases, you could start with the command
build run-with-test-panel
and give the class name of your test case like
org.argouml.
or
x.y
.Testz
org.argouml.
.
You will then get the output in the window.
You could run all tests in this way by specifying the special test suite
x.y
.GUITestz
org.argouml.util.DoAllTests
in the same way.
Every test case class imports the JUnit framework:
import junit.framework.*;
and it inherits TestCase
(i.e. junit.framework.TestCase
).
Methods that are tests must have names that start with "test" (i.e. all small t, e, s, t). This is a requirement of the JUnit framework.
Try to keep the test cases as short as possible. There is no need in cluttering them up just to beautify the output. Prefer
// Example from JUnit FAQ public void testIndexOutOfBoundsExceptionNotRaised() throws IndexOutOfBoundsException { ArrayList emptyList = new ArrayList(); Object o = emptyList.get(0); }
over
public void testIndexOutOfBoundsExceptionNotRaised() { try { ArrayList emptyList = new ArrayList(); Object o = emptyList.get(0); } catch (IndexOutOfBoundsException iobe) { fail("Index out of bounds exception was thrown."); } }
because the code is shorter, easier to maintain and you get a better error message from the JUnit framework.
A lot of times it is useful just to run the compiler to verify that
the signatures are correct on the interfaces. Therefor Linus has
thought it is a good idea to add methods called
compileTestStatics
,
compileTestConstructors
, and
compileTestMethods
that was thought to include correct calls to all static methods,
all public constructors, and all other public methods that are not
otherwise tested.
These methods are never called.
They serve as a guarantee that the public interface of a class will
never lose any of the functionality provided by its signature in an
uncontrolled way in just the same way as the test-methods serve as a
guarantee that no features will ever be lost.
Example 2.1. An example without javadoc comments
package org.argouml.uml.ui; import junit.framework.*; public class GUITestUMLAction extends TestCase { public GUITestUMLAction(String name) { super(name); } // Testing all three constructors. public void testCreate1() { UMLAction to = new UMLAction(new String("hejsan")); assert("Disabled", to.shouldBeEnabled()); } public void testCreate2() { UMLAction to = new UMLAction(new String("hejsan"), true); assert("Disabled", to.shouldBeEnabled()); } public void testCreate3() { UMLAction to = new UMLAction(new String("hejsan"), true, UMLAction.NO_ICON); assert("Disabled", to.shouldBeEnabled()); } }
and the corresponding no-GUI-class:
package org.argouml.uml.ui; import junit.framework.*; public class TestUMLAction extends TestCase { public TestUMLAction(String name) { super(name); } // Functions never actually called. Provided in order to make // sure that the static interface has not changed. private void compileTestStatics() { boolean t1 = UMLAction.HAS_ICON; boolean t2 = UMLAction.NO_ICON; UMLAction.getShortcut(new String()); UMLAction.getMnemonic(new String()); } private void compileTestConstructors() { new UMLAction(new String()); new UMLAction(new String(), true); new UMLAction(new String(), true, true); } private void compileTestMethods() { UMLAction to = new UMLAction(new String()); to.markNeedsSave(); to.updateEnabled(new Object()); to.updateEnabled(); to.shouldBeEnabled(); } }