Szukaj…
Uwagi
Parametr | Kontekst | Detale |
---|---|---|
@Przed zajęciami | Statyczny | Wywoływany, gdy klasa jest tworzona po raz pierwszy |
@Przed | Instancja | Wykonywany przed każdym testem w klasie |
@Test | Instancja | Należy zadeklarować każdą metodę do przetestowania |
@Po | Instancja | Wykonywany po każdym teście w klasie |
@Po zajęciach | Statyczny | Wykonany przed zniszczeniem klasy |
Przykładowy format klasy testowej
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() {}
}
}
Testy jednostkowe przy użyciu JUnit
Tutaj mamy klasę Counter
z metodami countNumbers()
i 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.*");
}
}
Aby przetestować tę klasę w jednostce, możemy użyć frameworka Junit. Dodaj junit.jar
do ścieżki klasy projektu. Następnie utwórz klasę przypadku testowego, jak poniżej:
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);
}
}
W swoim IDE możesz uruchomić tę klasę jako „walizkę testową Junit” i zobaczyć dane wyjściowe w GUI. W wierszu polecenia możesz skompilować i uruchomić przypadek testowy, jak poniżej:
\> javac -cp ,;junit.jar CounterTest.java
\> java -cp .;junit.jar org.junit.runner.JUnitCore CounterTest
Dane wyjściowe z pomyślnego uruchomienia testowego powinny wyglądać podobnie do:
JUnit version 4.9b2
..
Time: 0.019
OK (2 tests)
W przypadku niepowodzenia testu wyglądałoby to bardziej:
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
Lampy
Z Wikipedii :
Urządzenie testowe służy do konsekwentnego testowania jakiegoś elementu, urządzenia lub oprogramowania.
Może także poprawić czytelność testów poprzez wydobycie wspólnego kodu inicjalizacji / finalizacji z samych metod testowych.
Tam, gdzie wspólną inicjalizację można wykonać raz zamiast przed każdym testem, może to również skrócić czas potrzebny na uruchomienie testów.
Poniższy przykład ma na celu pokazanie głównych opcji dostarczonych przez JUnit. Załóżmy, że zainicjowanie klasy Foo
jest drogie:
public class Foo {
public Foo() {
// expensive initialization
}
public void cleanUp() {
// cleans up resources
}
}
Bar
innej klasy ma odniesienie do Foo
:
public class Bar {
private Foo foo;
public Bar(Foo foo) {
this.foo = foo;
}
public void cleanUp() {
// cleans up resources
}
}
Poniższe testy oczekują początkowego kontekstu Listy zawierającej pojedynczy 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();
}
}
W przykładzie @BeforeClass
opisywane sposób setupOnce()
jest wykorzystywane do tworzenia Foo
Obiekt, który jest kosztowny do inicjalizacji. Ważne jest, aby nie był modyfikowany przez żaden z testów, w przeciwnym razie wynik testu może zależeć od kolejności wykonywania poszczególnych testów. Chodzi o to, że każdy test jest niezależny i testuje jedną małą funkcję.
@Before
adnotacji @Before
setup()
konfiguruje kontekst testowy. Kontekst może być modyfikowany podczas wykonywania testu, dlatego należy go inicjować przed każdym testem. Równoważny efekt można osiągnąć, włączając kod zawarty w tej metodzie na początku każdej metody testowej.
Metoda @After
adnotacji tearDown()
czyści zasoby w kontekście testowym. Jest wywoływany po każdym wywołaniu testowym i jako taki jest często używany do zwolnienia zasobów przydzielonych w @Before
komentarzem @Before
.
@AfterClass
adnotowana tearDownOnce()
czyści zasoby po uruchomieniu wszystkich testów. Takie metody są zwykle używane do @BeforeClass
zasobów przydzielanych podczas inicjowania lub w @BeforeClass
adnotacjami @BeforeClass
. To powiedziawszy, prawdopodobnie najlepiej unikać zasobów zewnętrznych w testach jednostkowych, aby testy nie zależały od niczego poza klasą testów.
Testy jednostkowe z wykorzystaniem teorii
Z JavaDoc
Runner Theories pozwala przetestować określoną funkcjonalność względem podzbioru nieskończonego zestawu punktów danych.
Uruchamianie teorii
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
}
}
Metody opatrzone adnotacją @Theory
będą czytane jako teorie przez biegacza Theories.
Adnotacja @DataPoint
@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
}
}
Każde pole opatrzone @DataPoint
będzie używane jako parametr metody danego typu w teoriach. W powyższym przykładzie theoryMethod
będzie działać dwa razy z następującymi parametrami: ["str1", 2] , ["str2", 2]
@DataPoints adnotacja @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
}
}
Każdy element tablicy opatrzony adnotacją @DataPoints
będzie używany jako parametr metody danego typu w teoriach. W powyższym przykładzie theoryMethod
będzie działać cztery razy z następującymi parametrami: ["str1", 1], ["str2", 1], ["str1", 2], ["str2", 2]
Pomiar wydajności
Jeśli musisz sprawdzić, czy wykonanie metody testowania trwa zbyt długo, możesz to zrobić, wspominając o oczekiwanym czasie wykonania przy użyciu właściwości timeout adnotacji @Test. Jeśli wykonanie testu trwa dłużej niż ta liczba milisekund, powoduje to niepowodzenie metody testowej.
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());
}
}
W większości przypadków bez testu rozgrzewania JVM testString
nie powiedzie się. Ale testStringBuffer
i testStringBuilder
powinny pomyślnie przejść ten test.