Suche…
Bemerkungen
Parameter | Kontext | Einzelheiten |
---|---|---|
@Vor dem Unterricht | Statisch | Wird ausgeführt, wenn die Klasse zum ersten Mal erstellt wird |
@Vor | Beispiel | Vor jedem Test in der Klasse ausgeführt |
@Prüfung | Beispiel | Sollte jede Methode zum Testen deklariert werden |
@Nach dem | Beispiel | Wird nach jedem Test in der Klasse ausgeführt |
@Nach dem Unterricht | Statisch | Vor Zerstörung der Klasse ausgeführt |
Beispiel für das Testklassenformat
public class TestFeatureA {
@BeforeClass
public static void setupClass() {}
@Before
public void setupTest() {}
@Test
public void testA() {}
@Test
public void testB() {}
@After
public void tearDownTest() {}
@AfterClass
public static void tearDownClass() {}
}
}
Unit-Test mit JUnit
Hier haben wir eine Klasse Counter
mit Methoden countNumbers()
und hasNumbers()
.
public class Counter {
/* To count the numbers in the input */
public static int countNumbers(String input) {
int count = 0;
for (char letter : input.toCharArray()) {
if (Character.isDigit(letter))
count++;
}
return count;
}
/* To check whether the input has number*/
public static boolean hasNumber(String input) {
return input.matches(".*\\d.*");
}
}
Um diese Klasse zu testen, können wir das Junit-Framework verwenden. Fügen Sie die junit.jar
in Ihren Projektklassenpfad ein. Dann erstellen Sie die Testfallklasse wie folgt:
import org.junit.Assert; // imports from the junit.jar
import org.junit.Test;
public class CounterTest {
@Test // Test annotation makes this method as a test case
public void countNumbersTest() {
int expectedCount = 3;
int actualCount = Counter.countNumbers("Hi 123");
Assert.assertEquals(expectedCount, actualCount); //compares expected and actual value
}
@Test
public void hasNumberTest() {
boolean expectedValue = false;
boolean actualValue = Counter.hasNumber("Hi there!");
Assert.assertEquals(expectedValue, actualValue);
}
}
In Ihrer IDE können Sie diese Klasse als "Junit-Testfall" ausführen und die Ausgabe in der GUI sehen. In der Eingabeaufforderung können Sie den Testfall wie folgt kompilieren und ausführen:
\> javac -cp ,;junit.jar CounterTest.java
\> java -cp .;junit.jar org.junit.runner.JUnitCore CounterTest
Die Ausgabe eines erfolgreichen Testlaufs sollte folgendermaßen aussehen:
JUnit version 4.9b2
..
Time: 0.019
OK (2 tests)
Im Falle eines Testfehlers würde es eher so aussehen:
Time: 0.024
There was 1 failure:
1) CountNumbersTest(CounterTest)
java.lang.AssertionError: expected:<30> but was:<3>
... // truncated output
FAILURES!!!
Tests run: 2, Failures: 1
Fixtures
Von Wikipedia :
Ein Testgerät dient zum durchgängigen Testen eines Artikels, Geräts oder einer Software.
Es kann auch die Lesbarkeit von Tests verbessern, indem allgemeiner Initialisierungs- / Finalisierungscode aus den Testmethoden selbst extrahiert wird.
Wenn die gemeinsame Initialisierung einmal vor jedem Test ausgeführt werden kann, kann dies auch den Zeitaufwand für die Durchführung von Tests reduzieren.
Das folgende Beispiel zeigt die wichtigsten Optionen von JUnit. Angenommen, eine Klasse Foo
deren Initialisierung teuer ist:
public class Foo {
public Foo() {
// expensive initialization
}
public void cleanUp() {
// cleans up resources
}
}
Eine andere Klasse Bar
hat einen Verweis auf Foo
:
public class Bar {
private Foo foo;
public Bar(Foo foo) {
this.foo = foo;
}
public void cleanUp() {
// cleans up resources
}
}
Die folgenden Tests erwarten einen Anfangskontext einer Liste, die einen einzelnen Bar
.
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.List;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class FixturesTest {
private static Foo referenceFoo;
private List<Bar> testContext;
@BeforeClass
public static void setupOnce() {
// Called once before any tests have run
referenceFoo = new Foo();
}
@Before
public void setup() {
// Called before each test is run
testContext = Arrays.asList(new Bar(referenceFoo));
}
@Test
public void testSingle() {
assertEquals("Wrong test context size", 1, testContext.size());
Bar baz = testContext.get(0);
assertEquals(referenceFoo, baz.getFoo());
}
@Test
public void testMultiple() {
testContext.add(new Bar(referenceFoo));
assertEquals("Wrong test context size", 2, testContext.size());
for (Bar baz : testContext) {
assertEquals(referenceFoo, baz.getFoo());
}
}
@After
public void tearDown() {
// Called after each test is run
for (Bar baz : testContext) {
baz.cleanUp();
}
}
@AfterClass
public void tearDownOnce() {
// Called once after all tests have run
referenceFoo.cleanUp();
}
}
Im Beispiel ist die @BeforeClass
kommentierten Methode setupOnce()
wird verwendet , um das zu schaffen , Foo
- Objekt, das zu initialisieren teuer ist. Es ist wichtig, dass es durch keinen der Tests geändert wird, da das Ergebnis des Testlaufs von der Reihenfolge der einzelnen Tests abhängen kann. Die Idee ist, dass jeder Test unabhängig ist und ein kleines Feature testet.
Die mit @Before
annotierte Methode setup()
legt den @Before
. Der Kontext kann während der Testausführung geändert werden, weshalb er vor jedem Test initialisiert werden muss. Der äquivalente Effekt könnte erreicht werden, indem der in dieser Methode enthaltene Code zu Beginn jeder Testmethode eingefügt wird.
Die @After
annotierte Methode tearDown()
bereinigt Ressourcen im tearDown()
. Sie wird nach jedem @Before
aufgerufen und wird daher häufig dazu verwendet, Ressourcen zuzuweisen, die in einer mit @Before
annotierten Methode zugewiesen wurden.
Die annotierte tearDownOnce()
@AfterClass
Methode tearDownOnce()
bereinigt Ressourcen, sobald alle Tests ausgeführt wurden. Mit diesen Methoden werden normalerweise Ressourcen @BeforeClass
die während der Initialisierung oder in einer annotierten @BeforeClass
Methode zugewiesen wurden. Das heißt, es ist wahrscheinlich am besten, externe Ressourcen bei Komponententests zu vermeiden, damit die Tests nicht von etwas außerhalb der Testklasse abhängen.
Unit-Tests mit Theorien
Aus JavaDoc
Der Theories Runner ermöglicht das Testen einer bestimmten Funktionalität gegen eine Teilmenge einer unendlichen Menge von Datenpunkten.
Theorien laufen lassen
import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;
@RunWith(Theories.class)
public class FixturesTest {
@Theory
public void theory(){
//...some asserts
}
}
Mit @Theory
annotierte @Theory
werden vom Theories Runner als Theorien gelesen.
@DataPoint-Annotation
@RunWith(Theories.class)
public class FixturesTest {
@DataPoint
public static String dataPoint1 = "str1";
@DataPoint
public static String dataPoint2 = "str2";
@DataPoint
public static int intDataPoint = 2;
@Theory
public void theoryMethod(String dataPoint, int intData){
//...some asserts
}
}
Jedes mit @DataPoint
annotierte @DataPoint
wird als Methodenparameter eines bestimmten Typs in den Theorien verwendet. In obigem theoryMethod
wird theoryMethod
zweimal mit den folgenden Parametern ausgeführt: ["str1", 2] , ["str2", 2]
@DataPoints Annotation @RunWith (Theories.class) öffentliche Klasse FixturesTest {
@DataPoints
public static String[] dataPoints = new String[]{"str1", "str2"};
@DataPoints
public static int[] dataPoints = new int[]{1, 2};
@Theory
public void theoryMethod(String dataPoint, ){
//...some asserts
}
}
Jedes Element des mit @DataPoints
Annotation annotierten @DataPoints
wird als Methodenparameter eines bestimmten Typs in den Theorien verwendet. In dem obigen theoryMethod
wird theoryMethod
viermal mit den folgenden Parametern ausgeführt: ["str1", 1], ["str2", 1], ["str1", 2], ["str2", 2]
Leistungsmessung
Wenn Sie prüfen müssen, ob die Ausführung Ihrer Testmethode zu lange dauert, können Sie dies durch Angabe der erwarteten Ausführungszeit mit der timeout-Eigenschaft der @ Test-Annotation tun. Wenn die Testausführung länger als diese Anzahl von Millisekunden dauert, schlägt die Testmethode fehl.
public class StringConcatenationTest {
private static final int TIMES = 10_000;
// timeout in milliseconds
@Test(timeout = 20)
public void testString(){
String res = "";
for (int i = 0; i < TIMES; i++) {
res += i;
}
System.out.println(res.length());
}
@Test(timeout = 20)
public void testStringBuilder(){
StringBuilder res = new StringBuilder();
for (int i = 0; i < TIMES; i++) {
res.append(i);
}
System.out.println(res.length());
}
@Test(timeout = 20)
public void testStringBuffer(){
StringBuffer res = new StringBufferr();
for (int i = 0; i < TIMES; i++) {
res.append(i);
}
System.out.println(res.length());
}
}
In den meisten Fällen testString
ohne JVM- testString
fehl. testStringBuffer
und testStringBuilder
sollten diesen Test jedoch erfolgreich bestehen.