Zoeken…
Opmerkingen
Parameter | Context | Details |
---|---|---|
@Voor klas | Statisch | Wordt uitgevoerd wanneer de klasse voor het eerst wordt gemaakt |
@Voordat | Voorbeeld | Uitgevoerd vóór elke test in de klas |
@Test | Voorbeeld | Moet worden verklaard elke te testen methode |
@Na | Voorbeeld | Uitgevoerd na elke test in de klas |
@Na de les | Statisch | Uitgevoerd vóór vernietiging van de klas |
Voorbeeld van testklasse-indeling
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 testen met JUnit
Hier hebben we een klasse Counter
met methoden countNumbers()
en 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.*");
}
}
Om deze klasse te testen, kunnen we Junit-framework gebruiken. Voeg junit.jar
aan uw projectklassepad. Maak vervolgens de klasse Testcase zoals hieronder:
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 uw IDE kunt u deze klasse uitvoeren als "Junit-testcase" en de uitvoer in de GUI bekijken. In de opdrachtprompt kunt u de testcase compileren en uitvoeren zoals hieronder:
\> javac -cp ,;junit.jar CounterTest.java
\> java -cp .;junit.jar org.junit.runner.JUnitCore CounterTest
De output van een succesvolle testrun moet er ongeveer hetzelfde uitzien als:
JUnit version 4.9b2
..
Time: 0.019
OK (2 tests)
In het geval van een testfout zou het er meer uitzien als:
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
Wedstrijden
Van Wikipedia :
Een testopstelling is iets dat wordt gebruikt om een bepaald item, apparaat of software consequent te testen.
Het kan ook de leesbaarheid van tests verbeteren door de algemene initialisatie- / finalisatiecode uit de testmethoden zelf te extraheren.
Waar gemeenschappelijke initialisatie eenmaal kan worden uitgevoerd in plaats van vóór elke test, kan dit ook de hoeveelheid tijd verminderen die nodig is om tests uit te voeren.
In het onderstaande voorbeeld worden de belangrijkste opties van JUnit weergegeven. Ga uit van een klasse Foo
die duur is om te initialiseren:
public class Foo {
public Foo() {
// expensive initialization
}
public void cleanUp() {
// cleans up resources
}
}
Een andere klasse Bar
heeft een verwijzing naar Foo
:
public class Bar {
private Foo foo;
public Bar(Foo foo) {
this.foo = foo;
}
public void cleanUp() {
// cleans up resources
}
}
De onderstaande tests verwachten een eerste context van een lijst met één 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();
}
}
In het voorbeeld wordt de @BeforeClass
geannoteerde methode setupOnce()
gebruikt om het Foo
object te maken, wat duur is om te initialiseren. Het is belangrijk dat het door geen van de tests wordt gewijzigd, anders kan de uitkomst van de testrun afhankelijk zijn van de volgorde van uitvoering van de afzonderlijke tests. Het idee is dat elke test onafhankelijk is en één kleine functie test.
Met de methode @Before
annotated setup()
wordt de testcontext ingesteld. De context kan tijdens de uitvoering van de test worden gewijzigd en moet daarom vóór elke test worden geïnitialiseerd. Het equivalente effect kan worden bereikt door de code in deze methode op te nemen aan het begin van elke testmethode.
De @After
geannoteerde methode tearDown()
ruimt middelen binnen de test context. Het wordt genoemd na elke testoproep en wordt als zodanig vaak gebruikt om middelen vrij te maken die zijn toegewezen in een geannoteerde methode @Before
.
De @AfterClass
geannoteerde methode tearDownOnce()
ruimt middelen, zodra alle tests zijn uitgevoerd. Dergelijke methoden worden meestal gebruikt om middelen vrij te maken die zijn toegewezen tijdens de initialisatie of in een geannoteerde @BeforeClass
methode. Dat gezegd hebbende, is het waarschijnlijk het beste om externe bronnen in unit-tests te vermijden, zodat de tests niet afhankelijk zijn van iets buiten de testklasse.
Unit testen met behulp van theorieën
Van JavaDoc
De Theories runner maakt het mogelijk om een bepaalde functionaliteit te testen tegen een subset van een oneindige set datapunten.
Theorieën uitvoeren
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
}
}
Methoden geannoteerd met @Theory
worden gelezen als theorieën door Theories runner.
@DataPoint-annotatie
@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
}
}
Elk veld geannoteerd met @DataPoint
zal worden gebruikt als een parameterparameter van een bepaald type in de theorieën. In het bovenstaande voorbeeld theoryMethod
zal theoryMethod
twee keer worden uitgevoerd met de volgende parameters: ["str1", 2] , ["str2", 2]
@DataPoints annotatie @RunWith (Theories.class) public class 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
}
}
Elk element van de array dat is geannoteerd met @DataPoints
annotatie, wordt gebruikt als een parameterparameter van een bepaald type in de theorieën. In het bovenstaande voorbeeld theoryMethod
zal theoryMethod
vier keer worden uitgevoerd met de volgende parameters: ["str1", 1], ["str2", 1], ["str1", 2], ["str2", 2]
Prestatiemeting
Als u moet controleren of uw testmethode te lang duurt om uit te voeren, kunt u dat doen door uw verwachte uitvoeringstijd te vermelden met behulp van de timeout-eigenschap van @Test annotation. Als de testuitvoering langer duurt dan dat aantal milliseconden, zorgt dit ervoor dat een testmethode mislukt.
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 de meeste gevallen zal de JVM- testString
niet mislukken. Maar testStringBuffer
en testStringBuilder
moeten deze test met succes doorstaan.