...
En test-klasse består gjerne av mange test-metoder og hver test-metode vil typisk først rigge opp en eller flere instanser og så teste at disse oppfører seg som forventet. Ta test-klassen for Counter
-klassen som eksempel:
Code Block |
---|
public class CounterTest extends junit.framework.TestCase { import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; public class CounterTest { @Test public void testCounter() { Counter counter = new Counter(1, 3); assertEquals(1, counter.getCounter()); // sjekk om returverdi assertEquals(1er 1 assertTrue(counter.count()); // sjekk om returverdi er true assertEquals(2, counter.getCounter()); // sjekk om returverdi er 2 assertFalse(counter.count()); // sjekk om } returverdi er false assertEquals(3, counter.getCounter()); // sjekk om returverdi er 3 } @Test public void testGetCounter() { Counter counter = new Counter(1, 3); assertEquals(1, counter.getCounter()); counter.count(); assertEquals(2, counter.getCounter()); counter.count(); assertEquals(3, counter.getCounter()); } @Test public void testCount() { Counter counter = new Counter(1, 3); assertTrue(counter.count()); assertFalse(counter.count()); } } |
Her har vi tre test-metoder, som hver oppretter en instans og tester oppførselen til henholdsvis konstruktøren, getCounter
og count()
. Vi ser at alle rigger opp like instanser og dersom dette hadde vært mer enn én linje kode, så hadde det vært greit å samle denne koden i en egen hjelpemetode, f.eks. kalt riggInstansersetUp, som kalles i begynnelsen av hver test-metode:
Code Block |
---|
public class CounterTest extends junit.framework.TestCase { import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; public class CounterTest { private Counter counter = null; private Countervoid riggInstansersetUp() { counter = new Counter(1, 3); } } @Test public void testCounter() { setUp(); assertEquals(1, counter.getCounter()); // sjekk om returverdi er riggInstanser(1, 3); ... } 1 assertTrue(counter.count()); // sjekk om returverdi er true assertEquals(2, counter.getCounter()); // sjekk om returverdi er 2 assertFalse(counter.count()); // sjekk om returverdi er false assertEquals(3, counter.getCounter()); // sjekk om returverdi er 3 } @Test public void testGetCounter() { setUp(); Counter counter = new riggInstanserCounter(1, 3); assertEquals(1, ... } counter.getCounter()); counter.count(); assertEquals(2, counter.getCounter()); counter.count(); assertEquals(3, counter.getCounter()); } @Test public void testCount() { setUp(); Counter counter = new riggInstanserCounter(1, 3); ... } } assertTrue(counter.count()); assertFalse(counter.count()); } } |
Siden dette er et relativt vanlig tilfelle har JUnit-rammeverket innebygget støtte for en slik hjelpemetode. Denne er deklarert som protected void setUp() throws Exception
i TestCase-klassen og kalles automatisk av JUnit rammeverket før hver test-metode. Test-klasser som ønsker å rigge opp instanser, eller på annen måte gjøre forberedelser før testene, kan redefinere setUp()
-metoden med ønsket innhold. Hver test-metode er sikret at instansene er ferdig rigget opp, og siden dette skjer på nytt for hver test-metode, så kan disse herje fritt med instansene uten å tukle det til for de andre test-metodene. Koden over kan dermed skrives om slik:Ved å sette metoden til public og legget til @BeforeEach over testen vil den kjøres automatisk før hver test.
Code Block |
---|
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class CounterTest {
private Counter counter;
@BeforeEach
public |
Code Block |
public class CounterTest extends junit.framework.TestCase { private Counter counter = null; @Override protected void setUp() { counter = new Counter(1, 3); } @Test public void testCounter() { assertEquals(1, counter.getCounter()); // sjekk om returverdi er 1 assertTrue(counter.count()); // sjekk om returverdi er true assertEquals(2, counter.getCounter()); // sjekk om returverdi er 2 assertFalse(counter.count()); // sjekk om returverdi er false assertEquals(3, counter.getCounter()); // sjekk } om returverdi er 3 } @Test public void testGetCounter() { Counter counter = new Counter(1, 3); assertEquals(1, counter.getCounter()); counter.count(); assertEquals(2, counter.getCounter()); counter.count(); } assertEquals(3, counter.getCounter()); } @Test public void testCount() { Counter counter = new ... } }Counter(1, 3); assertTrue(counter.count()); assertFalse(counter.count()); } } |
I noen tilfeller vil det som rigges opp av setUp()
-metoden også måtte rigges ned, for ikke å forsøple systemet testene kjøres på. Det kan f.eks. være praktisk å opprette noen temporære datafiler i setUp()
-metoden, og da må de jo fjernes etterpå. Det vil ikke være særlig ryddig å gjøre dette i test-metodene selv, siden en da må bruke try/finally
for å sikre at det skjer uansett utfall av testen. Derfor støtter JUnit-rammeverket en tearDown()
-metode, som kalles automatisk etter at hver test-metode er kjørt, uansett om testen ble avbrutt eller ikke. Som for setUp()
er denne definert i TestCase
-klassen og egnet for redefineringdet bare å legge til @AfterAll over metoden. I tilfellet over er ikke en slik metode nødvendig (hver test-metode kjøres på en ny instans av CounterTest), men en test-klasse med tearDown()
-metode kunne sett slik ut:
Code Block |
---|
publicimport class CounterTest extends junit.framework.TestCase { private Counter counter = null; @Override protectedstatic org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class CounterTest { private Counter counter; @BeforeEach public void setUp() { counter = new Counter(1, 3); } @Override protected void tearDown } @AfterAll public void tearDown() { counter = null; } @Test public void testCounter() { assertEquals(1, counter.getCounter()); // sjekk om returverdi er 1 assertTrue(counter = null; } public void testCounter() { ... } .count()); // sjekk om returverdi er true assertEquals(2, counter.getCounter()); // sjekk om returverdi er 2 assertFalse(counter.count()); // sjekk om returverdi er false assertEquals(3, counter.getCounter()); // sjekk om returverdi er 3 } @Test public void testGetCounter() { Counter counter = new Counter(1, 3); assertEquals(1, counter.getCounter()); counter.count(); assertEquals(2, counter.getCounter()); counter.count(); } assertEquals(3, counter.getCounter()); } @Test public void testCount() { Counter counter = new ... } }Counter(1, 3); assertTrue(counter.count()); assertFalse(counter.count()); } } |
I praksis brukes ikke tearDown()
så ofte, men når setUp endrer tilstanden til systemet utenfor testene, så bør en vurdere å bruke den!
...