2016-02-26 32 views
5

Chcę testów jednostkowych tej metody przy użyciu Mockito/powermock:W jaki sposób mogę sfałszować żądanie Google geokodujące API za pomocą mockito/powermock?

@Service 
public class GoogleApiService { 

    private static final Logger logger = LoggerFactory.getLogger(GoogleApiService.class); 

    private static final String LANGUAGE = "es"; 

    private List<AddressType> addressTypes = Arrays.asList(
      AddressType.LOCALITY, 
      AddressType.ADMINISTRATIVE_AREA_LEVEL_2, 
      AddressType.ADMINISTRATIVE_AREA_LEVEL_1, 
      AddressType.COUNTRY 
    ); 

    @Autowired 
    private GeoApiContext geoApiContext; 

    public String getLocalityFromLatLng(LatLng latLng) throws Exception { 
     logger.debug("getLocalityFromLatLng"); 

     GeocodingResult[] geocodingResults = GeocodingApi.newRequest(geoApiContext) 
      .latlng(latLng) 
      .await(); 
     for (GeocodingResult geocodingResult : geocodingResults) { 
      AddressType addressType = geocodingResult.types[0]; 
      if (addressTypes.contains(addressType)) { 
       return geocodingResult.formattedAddress; 
      } 
     } 
     return StringUtils.EMPTY; 
    } 

} 

To co próbowałem:

@PrepareForTest(GeocodingApi.class) 
public class GoogleApiServiceUnitTest extends AbstractUnitTest { 

    private static final Double LATITUDE = -38.010403; 
    private static final Double LONGITUDE = -57.558408; 

    @Mock 
    private GeoApiContext geoApiContext; 

    @InjectMocks 
    private GoogleApiService googleApiService; 

    @Test 
    public void testGetLocalityFromLatLng() throws Exception { 

     LatLng latLng = new LatLng(LATITUDE, LONGITUDE); 
     GeocodingResult geocodingResult = new GeocodingResult(); 
     GeocodingResult[] geocodingResults = new GeocodingResult[] { geocodingResult }; 

     GeocodingApiRequest geocodingApiRequest = new GeocodingApiRequest(geoApiContext); 
     geocodingApiRequest.latlng(latLng); 

     mockStatic(GeocodingApi.class); 

     // when(GeocodingApi.newRequest(geoApiContext)) 
      // .thenReturn(geocodingApiRequest); 

     // when(GeocodingApi.newRequest(geoApiContext).latlng(latLng)) 
      // .thenReturn(geocodingApiRequest); 

     when(GeocodingApi.newRequest(geoApiContext).latlng(latLng).await()) 
      .thenReturn(geocodingResults); 

     String locality = googleApiService.getLocalityFromLatLng(latLng); 

     assertThat(locality, is(notNullValue())); 

     verifyStatic(times(1)); 
     GeocodingApi.newRequest(geoApiContext).latlng(latLng).await(); 

     verifyNoMoreInteractions(geoApiContext); 
    } 

} 

Dostaję NullPointerException. Oto ślad stosu:

java.lang.NullPointerException 
at com.google.maps.PendingResultBase.await(PendingResultBase.java:56) 
at com.beermap.server.unit.service.GoogleApiServiceUnitTest.testGetLocalityFromLatLng(GoogleApiServiceUnitTest.java:57) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:310) 
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:89) 
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:127) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282) 
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87) 
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120) 
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34) 
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:122) 
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:106) 
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53) 
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59) 
at org.junit.runner.JUnitCore.run(JUnitCore.java:137) 
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78) 
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212) 
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) 

jest w linii Oczekujcie() wezwanie

EDIT: to jak to wygląda teraz, to nadal nie działa

btw, @RunWith(PowerMockRunner.class) jest w AbstractUnitTest

@Test 
public void testGetLocalityFromLatLng() throws Exception { 

    LatLng latLng = new LatLng(LATITUDE, LONGITUDE); 
    GeocodingResult geocodingResult = new GeocodingResult(); 
    geocodingResult.types = new AddressType[] { AddressType.LOCALITY }; 
    geocodingResult.formattedAddress = FORMATTED_ADDRESS; 
    GeocodingResult[] geocodingResults = new GeocodingResult[] { geocodingResult }; 

    GeocodingApiRequest geocodingApiRequest = mock(GeocodingApiRequest.class); 

    mockStatic(GeocodingApi.class); 

    when(geocodingApiRequest.latlng(latLng)).thenReturn(geocodingApiRequest); 
    when(geocodingApiRequest.await()).thenReturn(geocodingResults); // NPE here 
    when(GeocodingApi.newRequest(geoApiContext)).thenReturn(geocodingApiRequest); 

    String locality = googleApiService.getLocalityFromLatLng(latLng); 

    assertThat(locality, is(notNullValue())); 

    // verifyStatic(times(1)); 
    // GeocodingApi.newRequest(geoApiContext).latlng(latLng).await(); 

    // verifyNoMoreInteractions(geoApiContext); 

} 

i stos:

java.lang.NullPointerException 
at com.google.maps.PendingResultBase.makeRequest(PendingResultBase.java:79) 
at com.google.maps.PendingResultBase.await(PendingResultBase.java:55) 
at com.beermap.server.unit.service.GoogleApiServiceUnitTest.testGetLocalityFromLatLng(GoogleApiServiceUnitTest.java:56) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:310) 
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:89) 
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:127) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282) 
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87) 
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120) 
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34) 
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:122) 
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:106) 
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53) 
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59) 
at org.junit.runner.JUnitCore.run(JUnitCore.java:137) 
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78) 
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212) 
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) 

Z góry dziękuję

+0

można dodać pustego śladu wskaźnik stosu? –

+0

@NickDeFazio done –

Odpowiedz

3

Jest tutaj kilka błędów, które świadczą o niezrozumieniu kpiny. Przeanalizujmy je:

Na początku mam nadzieję, że to pomyłka już przeszłość, nie masz @RunWith(PowerMockRunner.class), w przeciwnym razie dostaniesz inny wyjątek.

Po drugie, ta skomentowana linia ma rację: when(GeocodingApi.newRequest(geoApiContext)).thenReturn(geocodingApiRequest);. Kiedy statyczna metoda GeocodingApi następnie chcesz zwrócić geocodingApiRequest.

W końcu, ale najważniejszy punkt, linia ta jest błędna: będzie wyśmiewany when(GeocodingApi.newRequest(geoApiContext).latlng(latLng).await()).thenReturn(geocodingResults);

Tylko jeden statyczny wezwanie tutaj: GeocodingApi.newRequest(geoApiContext).

I instancja obiektu zostanie zwrócona, ponieważ tworzysz nową instancję GeocodingApiRequest geocodingApiRequest = new GeocodingApiRequest(geoApiContext);.

Metoda latlng(latLng) jest wywoływana z obiektu rzeczywistego. I to naprawdę połączenie, a nie wyśmiewane. Ale wydaje mi się, że ty też chcesz drwić z tego.

Potem niech wyśmiewać go: GeocodingApiRequest geocodingApiRequest = mock(GeocodingApiRequest.class);

później. mock wszystkie połączenia, które muszą być wyśmiewany:

when(geocodingApiRequest.latlng(latLng)).thenReturn(geocodingApiRequest); 
when(geocodingApiRequest.await()).thenReturn(geocodingResults); 

Innym błędem, ale tak ważny jak poprzednie i bardziej oczywisty: wymagana plików nie jest ustawiony na geocodingResult.

GeocodingResult geocodingResult = new GeocodingResult(); 
geocodingResult.types = new AddressType[]{ AddressType.LOCALITY}; 
geocodingResult.formattedAddress = "Some address"; 

Pełne badanie robocze:

@RunWith(PowerMockRunner.class) 
@PrepareForTest({GeocodingApi.class, GeocodingApiRequest.class}) 
public class GoogleApiServiceUnitTest { 

    private static final Double LATITUDE = -38.010403; 
    private static final Double LONGITUDE = -57.558408; 

    @Mock 
    private GeoApiContext geoApiContext; 

    @InjectMocks 
    private GoogleApiService googleApiService; 

    @Test 
    public void testGetLocalityFromLatLng() throws Exception { 

     LatLng latLng = new LatLng(LATITUDE, LONGITUDE); 
     GeocodingResult geocodingResult = new GeocodingResult(); 
     geocodingResult.types = new AddressType[]{ AddressType.LOCALITY}; 
     geocodingResult.formattedAddress = "Some address"; 

     GeocodingResult[] geocodingResults = new GeocodingResult[] { geocodingResult }; 

     GeocodingApiRequest geocodingApiRequest = mock(GeocodingApiRequest.class); 
     when(geocodingApiRequest.latlng(latLng)).thenReturn(geocodingApiRequest); 
     when(geocodingApiRequest.await()).thenReturn(geocodingResults); 

     mockStatic(GeocodingApi.class); 

     when(GeocodingApi.newRequest(eq(geoApiContext))) 
      .thenReturn(geocodingApiRequest); 

     String locality = googleApiService.getLocalityFromLatLng(latLng); 

     assertThat(locality, is(notNullValue())); 

     verifyStatic(times(1)); 
     GeocodingApi.newRequest(geoApiContext); 

     // add verification other mock if you really need it 

     verifyNoMoreInteractions(geoApiContext); 
    } 
} 
+0

dziękuję, pomaga, ale nadal nie działa, wciąż otrzymuję NPE w oczekiwaniu(), edytowałem mój test (patrz edycja w odpowiedzi), a także skopiuj/wklej rozwiązanie, a oba nie ta sama linia. –

+0

Czy dodałeś "GeocodingApiRequest.class" do "@PrepareForTest"? –

+0

oh, zapomniałem, ale dodałem teraz i nadal nie działa .. ten sam błąd –