Muszę napisać testy JUnit dla starej aplikacji, która jest źle zaprojektowana i pisze wiele komunikatów o błędach na standardowe wyjście. Gdy getResponse(String request)
metoda zachowuje się poprawnie, zwraca odpowiedź XML:
@BeforeClass
public static void setUpClass() throws Exception {
Properties queries = loadPropertiesFile("requests.properties");
Properties responses = loadPropertiesFile("responses.properties");
instance = new ResponseGenerator(queries, responses);
}
@Test
public void testGetResponse() {
String request = "<some>request</some>";
String expResult = "<some>response</some>";
String result = instance.getResponse(request);
assertEquals(expResult, result);
}
Ale kiedy otrzyma zniekształcony XML lub nie zrozumie żądania, zwraca null
i zapisuje pewne rzeczy na standardowym wyjściu.
Czy jest jakiś sposób na potwierdzenie wyjścia konsoli w JUnit? Aby złapać przypadki takie jak:
System.out.println("match found: " + strExpr);
System.out.println("xml not well formed: " + e.getMessage());
Odpowiedzi:
korzystanie z ByteArrayOutputStream i System.setXXX jest proste:
przykładowe przypadki testowe:
Użyłem tego kodu do przetestowania opcji wiersza poleceń (stwierdzenie, że -version wyświetla ciąg wersji itp.)
Edycja: wcześniejsze wersje tej odpowiedzi wywoływane
System.setOut(null)
po testach; To jest przyczyna, do której odwołują się komentatorzy NullPointerExceptions.źródło
NullPointerException
W innych testach napotkałem po ustawieniu strumienia błędów o wartości zerowej, jak sugerowano powyżej (injava.io.writer(Object)
, wywoływany wewnętrznie przez moduł sprawdzania poprawności XML). Zamiast tego sugerowałbym zapisanie oryginału w polu:oldStdErr = System.err
i przywrócenie tego w@After
metodzie.Wiem, że to stary wątek, ale jest do tego przyjemna biblioteka:
Zasady systemowe
Przykład z dokumentów:
Pozwoli również na przechwytywanie
System.exit(-1)
i inne rzeczy, dla których narzędzie wiersza poleceń musiałoby zostać przetestowane.źródło
Zamiast przekierowywać
System.out
, przefakturowałbym klasę, która używaSystem.out.println()
, przekazując aPrintStream
jako współpracownika, a następnie używającSystem.out
w produkcji i Test Spy w teście. To znaczy, użyj Dependency Injection, aby wyeliminować bezpośrednie użycie standardowego strumienia wyjściowego.W produkcji
W teście
Dyskusja
W ten sposób testowana klasa staje się testowalna przez proste refaktoryzowanie, bez potrzeby pośredniego przekierowywania standardowego wyjścia lub niejasnego przechwytywania za pomocą reguły systemowej.
źródło
ConsoleWriter
jest to temat testowy,Możesz ustawić strumień wydruku System.out za pomocą setOut () (oraz dla
in
ierr
). Czy możesz przekierować to do strumienia wydruku, który zapisuje ciąg, a następnie to sprawdzić? To wydaje się być najprostszym mechanizmem.(Na pewnym etapie zalecałbym konwersję aplikacji do struktury rejestrowania - ale podejrzewam, że już o tym wiesz!)
źródło
Nie na temat, ale na wypadek, gdyby niektóre osoby (takie jak ja, kiedy pierwszy raz znalazłem ten wątek) mogły być zainteresowane przechwytywaniem danych wyjściowych dziennika za pośrednictwem SLF4J, JUnit do testowania wspólnych
@Rule
może pomóc:Zastrzeżenie :
log4j
,log4j2
ilogback
są dostępne w tej chwili, ale jestem szczęśliwy, aby dodać więcej.źródło
Odpowiedź @dfa jest świetna, więc zrobiłem krok dalej, aby umożliwić testowanie bloków wyjścia.
Najpierw stworzyłem
TestHelper
metodą,captureOutput
która akceptuje annoymiczną klasęCaptureTest
. Metoda captureOutput polega na ustawianiu i niszczeniu strumieni wyjściowych. Jeśli realizacjaCaptureOutput
„stest
metoda jest wywoływana, to ma dostęp do wyjścia wygeneruje dla bloku testowego.Źródło dla TestHelper:
Zauważ, że TestHelper i CaptureTest są zdefiniowane w tym samym pliku.
Następnie w teście możesz zaimportować static captureOutput. Oto przykład z użyciem JUnit:
źródło
Jeśli korzystasz z Spring Boot (wspomniałeś, że pracujesz ze starą aplikacją, więc prawdopodobnie nie jesteś, ale może być przydatny dla innych), możesz użyć org.springframework.boot.test.rule.OutputCapture W następujący sposób:
źródło
W oparciu o odpowiedź @ dfa i inną odpowiedź, która pokazuje, jak przetestować System.in , chciałbym udostępnić moje rozwiązanie, aby przekazać dane wejściowe do programu i przetestować jego wyniki.
Jako odniesienie używam JUnit 4.12.
Powiedzmy, że mamy ten program, który po prostu replikuje dane wejściowe na dane wyjściowe:
Aby to przetestować, możemy użyć następującej klasy:
Nie wyjaśnię wiele, ponieważ uważam, że kod jest czytelny i zacytowałem swoje źródła.
Po uruchomieniu JUnit
testCase1()
będzie wywoływał metody pomocnicze w kolejności, w jakiej się pojawiają:setUpOutput()
, z powodu@Before
adnotacjiprovideInput(String data)
, wywoływany ztestCase1()
getOutput()
, wywoływany ztestCase1()
restoreSystemInputOutput()
, z powodu@After
adnotacjiNie testowałem,
System.err
ponieważ go nie potrzebowałem, ale powinien być łatwy do wdrożenia, podobnie jak testowanieSystem.out
.źródło
Nie chcesz przekierowywać strumienia system.out, ponieważ przekierowuje to dla CAŁEGO JVM. Cokolwiek innego działającego na JVM może zostać pomieszane. Istnieją lepsze sposoby testowania wejścia / wyjścia. Spójrz na kody pośredniczące / kpiny.
źródło
Pełny przykład JUnit 5 do przetestowania
System.out
(wymień część when):źródło
Nie można drukować bezpośrednio przy użyciu system.out.println lub interfejsu API rejestratora podczas korzystania z JUnit . Ale jeśli chcesz sprawdzić jakieś wartości, możesz po prostu użyć
Wyrzuci poniżej błędu asercji:
Twoja wartość powinna wynosić 21,92. Teraz, jeśli będziesz testować przy użyciu tej wartości, jak poniżej, Twój test przejdzie.
źródło
na zewnątrz
dla błędu
źródło
@Rule
zamiast, zamiast robić to bezpośrednio w teście. W szczególności, jeśli twoje twierdzenie nie powiedzie się, drugieSystem.setOut/Err
połączenie nie zostanie osiągnięte.