2016-02-26 43 views
5

我想要的單元測試使用的Mockito/powermock這種方法:如何使用mockito/powermock模擬Google的Geocoding API請求?

@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; 
    } 

} 

這是我曾嘗試:

@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); 
    } 

} 

我得到NullPointerException異常。這裏是堆棧跟蹤:

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) 

在的await()調用線

編輯:這是現在的樣子,現在還沒有工作

順便說一句,@RunWith(PowerMockRunner.class)是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); 

} 

和堆棧:

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) 

在此先感謝

+0

您可以添加空指針堆棧跟蹤? –

+0

@NickDeFazio完成 –

回答

3

這裏有幾個錯誤,它表明你有誤解的嘲笑。讓我們分析一下:

起初,我希望它是複製過去的錯誤,你沒有@RunWith(PowerMockRunner.class),否則你會得到另一個例外。

第二點,這個註釋掉的行是對的when(GeocodingApi.newRequest(geoApiContext)).thenReturn(geocodingApiRequest);。當GeocodingApi的靜態方法時,則要返回geocodingApiRequest

最後,但最重要的一點,這條線是不正確的:when(GeocodingApi.newRequest(geoApiContext).latlng(latLng).await()).thenReturn(geocodingResults);

只有一個靜態的通話將被嘲笑這裏:GeocodingApi.newRequest(geoApiContext)

而真實對象的實例將被返回,因爲您創建了一個新實例 GeocodingApiRequest geocodingApiRequest = new GeocodingApiRequest(geoApiContext);

latlng(latLng)方法是從真正的對象中調用的。這是真正的電話,而不是嘲笑。但在我看來,你也想嘲笑它。

然後讓我們嘲笑它:GeocodingApiRequest geocodingApiRequest = mock(GeocodingApiRequest.class);

後。需要模擬所有呼叫被嘲笑:

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

另一個錯誤,但由於以前的多明明那麼重要:所需的文件沒有設置geocodingResult

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

完整的工作測試:

@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

謝謝,它有幫助,但仍然不工作,我仍然在等待()呼叫,我編輯了我的測試(請參閱編輯答案),還複製/粘貼您的解決方案,都失敗了同一條線。 –

+0

您是否已將'GeocodingApiRequest.class'添加到'@PrepareForTest'? –

+0

哦,我忘了,但我現在加了,仍然沒有工作..同樣的錯誤 –