2012-06-12 8 views
25

Napisałem kod, który wywołuje API klienta z Jersey, które z kolei wywołuje usługę internetową, która jest poza moją kontrolą. Nie chcę, aby mój test jednostki wywoływał rzeczywistą usługę sieciową.Jak mogę sprawdzić kod jednostki, który wywołuje interfejs API klienta Jersey?

Jakie jest najlepsze podejście do pisania testu jednostkowego dla kodu wywołującego interfejs API klienta Jersey? Czy powinienem używać interfejsu API serwera Jersey, aby napisać usługę WWW JAX-RS, a następnie użyć testowej platformy testowej do testowania urządzenia? A może powinienem wyśmiewać połączenia z serwisem w Jersey? Mam dostęp do JMock. Czy powinienem spróbować innego podejścia?

Podczas moich badań znalazłem this discussion opisujący różne opcje, ale znalazłem kompletne rozwiązanie. Czy są dostępne przykłady kodu pokazujące sugerowane podejście JUnit? Nie mogłem znaleźć żadnej dokumentacji z Jersey.

Oto odpowiedni kod źródłowy:

public String getResult(URI uri) throws Exception { 
    // error handling code removed for clarity 
    ClientConfig clientConfig = new DefaultClientConfig(); 
    Client client = Client.create(clientConfig); 
    WebResource service = client.resource(uri); 
    String result = service.accept(accept).get(String.class); 
    return result; 
} 

Oto przykłady kodu testu chciałbym przekazać. Chciałbym przetestować (1) przekazanie prawidłowego identyfikatora URI i otrzymanie prawidłowego ciągu wstecz oraz (2) przekazanie nieprawidłowego (z jakiegokolwiek powodu - nieosiągalnego lub nieautoryzowanego) identyfikatora URI i odzyskanie wyjątku. powyżej

@Test 
public void testGetResult_ValidUri() throws Exception { 
    String xml = retriever.getResult(VALID_URI); 
    Assert.assertFalse(StringUtils.isBlank(xml)); 
} 

@Test(expected = IllegalArgumentException.class) 
public void testGetResult_InvalidUri() throws Exception { 
    retriever.getResult(INVALID_URI); 
} 

Wszystko jest prosty opis tego, co robi mój kod. W rzeczywistości na wierzchu znajduje się warstwa, która akceptuje dwa identyfikatory URI, najpierw próbuje wywołać pierwszy identyfikator URI, a jeśli ten identyfikator URI nie powiedzie się, próbuje wywołać drugi identyfikator URI. Chciałbym mieć testy jednostkowe obejmujące (1) pierwszy URI się powiedzie, (2) pierwszy URI się nie udał, a drugi URI się powiódł i (3) oba URI uległy awarii. Ten kod jest wystarczająco złożony, że chcę przetestować te różne scenariusze przy użyciu JUnit, ale aby to zrobić, muszę uruchomić rzeczywiste autonomiczne usługi sieciowe lub wyszydzić wywołania interfejsu API klienta Jersey.

+0

Co dokładnie chcesz przetestować w tej metodzie? Jakie są krytyczki, ten test jest zaliczony? – dbf

+0

Cóż, jeśli chcesz wykonać test jednostkowy, musisz mieć odpowiednie usługi funkcjonalne. – iDroid

+0

@dbf Zaktualizowałem pytanie, które chcę przetestować (1) przekazanie w poprawnym URI i otrzymanie prawidłowego ciągu wstecz i (2) przekazanie nieważnego (z jakiegokolwiek powodu - nieosiągalnego lub nieautoryzowanego) URI i uzyskanie wyjątku plecy. – BennyMcBenBen

Odpowiedz

12

Spróbuj użyć Mockito lub Easymocka do kpienia z rozmów serwisowych. Trzeba wyśmiać tylko te metody, które są faktycznie używane - nie ma potrzeby kpić z każdej metody. Możesz utworzyć próbny obiekt dla klasy WebResource, a następnie pozorować akceptację metody call.

W @ BeforeClass/@ Przed testu JUnit sposób napisać coś podobnego (np Mockito)

WebResource res = mock(WebResource.class); 
when(res.accept(something)).thenReturn(thatWhatYouWant); 

Następnie w badaniach można użyć Res obiekt jakby to był prawdziwy obiekt i wywołać metodę makiety na nim. Zamiast zwracania wartości można również zgłaszać wyjątki. Mockito jest całkiem fajny.

+1

To jest poprawna odpowiedź. Wykonanie całej usługi internetowej polega na testowaniu kodu Jersey, kiedy już wiem, że działa. Chcę przetestować mój kod. Skończyło się na tym, że musiałam przekierowywać połączenia do kodu z Jersey do innej klasy, dodając setera i kpiąc z nowej klasy. To zadziałało doskonale i pozwoliło mi przetestować różne scenariusze, które chciałem przetestować. Mój zespół korzysta z JMock, więc skończyło się na tym, ale zrobi to każda szydercza struktura. – BennyMcBenBen

+0

Jestem trochę zdezorientowany, ponieważ strona Mockito stwierdza "Nie kpisz z tego, że nie jesteś właścicielem!" Gdzie narysujemy linię, na temat tego, co możemy kpić a czym nie. Czy istnieje lepszy sposób? –

0

Wystarczy zaimplementować usługę podobną do usługi, aw konfiguracji testu urządzenia uruchom usługę za pomocą HttpServerFactory.

11

Zwykle to, czego naprawdę szukasz, to "Czy sposób, w jaki używam DSL klienta Jersey, powoduje wysłanie żądania do poprawnego adresu URL z poprawnymi parametrami ładunku i adresu URL". Testowanie to z Mockito jest naprawdę gadatliwy i kod instalacyjny zazwyczaj kończy się szuka czegoś takiego:

when(authentication.queryParam(eq("sa"), anyBoolean())).thenReturn(testAuthentication); 
    when(testAuthentication.resolveTemplate("channel", "smf")).thenReturn(testAuthentication); 
    when(testAuthentication.request(
      MediaType.APPLICATION_JSON_TYPE)).thenReturn(mockRequestBuilder); 
    when(mockRequestBuilder.post(any(Entity.class))).thenReturn(mockResponse); 
    when(mockResponse.readEntity(ResponseWrapper.class)).thenReturn(successfulAuthResponse()); 

I to jest w zasadzie tylko dla pojedynczego żądania REST. Jest zbyt obszerny i zamiast testować oczekiwany rezultat, po prostu replikuje kroki, które uważasz za poprawne w korzystaniu z DSL klienta Jersey.

Zamiast powyższego chciałbym kpić z prostej usługi.W tym celu użyłem WireMock, który uruchamia serwer Jetty i gdzie mogę dodawać elementy takie jak: "oczekuję żądania na ten adres URL, odpowiadam za pomocą tego komunikatu i sprawdzam, czy ładunek jest taki".

Wiem, że jest to test integracyjny i jest nieco wolniejszy niż użycie samego Mockito, ale cenię testowanie prawdziwego wyniku, a ja cenię czytelność testów w tym przypadku.

konfiguracji opartej na WireMock Test Client Jersey wygląda mniej więcej tak:

@Test 
public void exactUrlOnly() { 
    stubFor(get(urlEqualTo("/some/thing")) 
      .willReturn(aResponse() 
       .withHeader("Content-Type", "text/plain") 
       .withBody("Hello world!"))); 

    assertThat(testClient.get("/some/thing").statusCode(), is(200)); 
    assertThat(testClient.get("/some/thing/else").statusCode(), is(404)); 
} 
+0

+1 za WireMock - świetne narzędzie. W moim przypadku Mockito nie mógł kpić z WebResource.Builder (final), rozwiązany dzięki WireMock – denismo

Powiązane problemy