Java Testing
junit
Man erzeugt eine neue Klasse, in der mit @Test markierte Methoden einzelne Tests ausführen
import org.junit.Before;
import org.junit.Test;
public class MyCTestClass
{
@Before
public void Myinit()
{
...
}
@Test
public void TestAddMethod()
{
assertTrue(a.add(ZERO).equals(a));
assertTrue(a.add(b).equals(b.add(a)));
}
@Test
public void isDivOK()
{
assertTrue(a.div(ONE).equals(a));
assertTrue(a.mult(b).div(b).equals(a));
}
@Test(expected=NullPointerException.class)
public void nullParameter()
{
a.add(null);
}
}
Diese Tests können dann über die Kommandozeile, die IDE oder im Buildprozess ausgeführt werden.
Man sollte sich vorher überlegen, ob man die JUnit Testklassen direkt im normalen Source Ordner ablegt, wo auch die zu testenden Klassen liegen
build
src
de
tgunkel
Foo.src
FooTest.src
oder ob man parallel zum Source Ordner eine weitere Ordner Hierarchie einzieht in der dann die Tests liegen
build
src
de
tgunkel
Foo.src
src_tests
de
tgunkel
FooTest.src
Legt man sie im selben Ordner ab, werden die Klassen direkt mitkompiliert und man muss seinen Buildprozess nicht anpassen. Dafür ist es aufwendiger die Tests vom normalen Code zu trennen, z.B. wenn man die Testklassen nicht mit ausliefern möchte. Das Ergebnis kann man dann in einem Ordner ablegen lassen. Andere Tools können die Ergebnisse in diesem Ordner dann auswerten.
If you wan to compare two container use hamcrest
import static org.hamcrest.Matchers.contains;
List<String> result=...
assertThat(result, contains("foo", "bar"));
If order should not matter use
instead.
If you have 2 lists you can also do it like this
assertThat(actual, is(expected));
If tests should not run under all conditions (e.g. not on all days)
@Test public void test() {
assumeThat(true);
assertEquals(..., ...);
}
JUnit Test über die Kommandozeile
JUnit Tests in Eclipse
Eclipse unterstützt direkt JUnit Tests
JUnit Tests mit ant
Man kann direkt aus ant heraus die JUnit Tests durchlaufen lassen
<path id="classpath">
<fileset file="MyProject.jar" />
</path>
<path id="classpath_tests">
<fileset file="MyProjectTests.jar" />
<fileset file="junit-4.8.1.jar" />
</path>
<target name="unittests" description="Execute unit tests" depends="compile_tests,jar_tests">
<echo message="Unit tests ..." />
<junit printsummary="withOutAndErr" fork="no" failureproperty="junit.failure" haltonfailure="false">
<classpath refid="classpath" />
<classpath refid="classpath_tests" />
<formatter type="xml" usefile="true" />
<batchtest todir="${junitTestResults}">
<fileset dir="src_tests">
<include name="**/*.java"/>
</fileset>
</batchtest>
</junit>
<echo message="Unit tests done" />
</target>
So kann man steuern, ob mögliche Stacktraces auf der Konsole landen <!-- <formatter type="xml" usefile="true" /> --> <formatter type="plain" usefile="false"/>
JUnit und log4j
{
@BeforeClass
public static void staticInit()
{
// make log4j happy
BasicConfigurator.configure();
}
}
Junit, ant und Stacktrace für Tests auf Console
Mockito
Wenn es für Unit Tests zu aufwendig ist Testobjekte zu erstellen kann man mit Mockito leere Objekte erstellen lassen die dann bei bestimmten Aufrufen die Werte zurückliefern, die man für Tests braucht. Anstatt z.B. für einen Test wirklich eine Collection mit sehr vielen Elementen zu erzeugen, kann man so eine Mock Collection erzeugen die einfach behauptet sie hätte die gewünschte Anzahl an Elementen.
public class OfferListViewWithStatsTest {
@Test
public void test() {
final Collection tst = Mockito.mock(Collection.class);
Mockito.when(tst.size()).thenReturn(10000000);
// just create an empty Mock object which claims to be of the right class
static final List<String> list5= Mockito.mock(List.class);
// if anybody asks the test object about its size, just lie and say its 5
Mockito.when(list5.size()).thenReturn(5);
// if anybody wants to get an element from the list, just return the same element. But also check that the position is within the size we already lied about
Mockito.when(list5.get(ArgumentMatchers.anyInt())).then(new Answer<String>() {
@Override
public String answer(final InvocationOnMock invocation) throws Throwable {
final Object[] args = invocation.getArguments();
final int pos = (int) args[0];
if (pos >= 0 && pos < 5) {
return "DUMMY";
}
throw new IndexOutOfBoundsException();
}
});
// now we are ready to use the test object
assertEquals(5, TestValues.list5.size());
assertEquals("DUMMY", TestValues.list5.get(4));
}
}
If you want to mock a method call that has parameters use org.mockito.ArgumentMatchers, e.g. ArgumentMatchers.any()
Hudson / Jenkins
Hudson (Oracle) bzw. Jenkins (freier Fork) ist ein Tool zur kontinuierlichen Überwachung von Softwareprojekten. Damit kann man z.B. periodisch aus einem Subversion Server Code auschecken, in compilieren und danach die Ergebisse der JUnit Test überprüfen. Über die Ergebnisse können die Entwickler dann direkt informiert werden.