本文介绍了如何使用Mockito/Powermock模拟Google的Geocoding API请求?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用Mockito/Powermock对这种方法进行单元测试:

I want to unit test this method using 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;
    }

}

这是我尝试过的:

@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.这是堆栈跟踪:

i'm getting NullPointerException. Here is the stack trace:

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()呼叫行中

is in the await() call line

这是现在的样子,它仍然无法正常工作

this is how it looks now, it is still not working

btw,@RunWith(PowerMockRunner.class)在AbstractUnitTest中

btw, @RunWith(PowerMockRunner.class) is in 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)

预先感谢

推荐答案

这里有几个错误,表明您对嘲笑有误解.让我们对其进行分析:

There are several mistakes here and it show that you have misunderstanding of mocking. Let analyse them:

起初,我希望这是一个复制过去的错误,您没有@RunWith(PowerMockRunner.class),否则您将得到另一个异常.

At first, I hope it's copy-past mistake, you don't have @RunWith(PowerMockRunner.class), otherwise you'll get another exception.

第二点,该注释掉的行是正确的when(GeocodingApi.newRequest(geoApiContext)).thenReturn(geocodingApiRequest);.当GeocodingApi的静态方法时,您要返回geocodingApiRequest.

Second point, this commented out line is right when(GeocodingApi.newRequest(geoApiContext)).thenReturn(geocodingApiRequest);. When static method of the GeocodingApithen you want to return geocodingApiRequest.

最后但最重要的一点是,此行不正确:when(GeocodingApi.newRequest(geoApiContext).latlng(latLng).await()).thenReturn(geocodingResults);

At last, but most important point, this line is incorrect: when(GeocodingApi.newRequest(geoApiContext).latlng(latLng).await()).thenReturn(geocodingResults);

此处将仅模拟一个静态调用:GeocodingApi.newRequest(geoApiContext).

Only one static call will be mocked here: GeocodingApi.newRequest(geoApiContext).

真正对象的实例将返回,因为您创建了一个新实例GeocodingApiRequest geocodingApiRequest = new GeocodingApiRequest(geoApiContext);.

And instance of really object will be return, because you create a new instanceGeocodingApiRequest geocodingApiRequest = new GeocodingApiRequest(geoApiContext);.

latlng(latLng)方法是从真正的对象中调用的.这是真正的召唤,而不是嘲笑.但是在我看来,您也想嘲笑它.

The latlng(latLng) method is called from really object. And it's really call, not mocked. But seems to me you also want to mock it.

然后让我们模拟一下:GeocodingApiRequest geocodingApiRequest = mock(GeocodingApiRequest.class);

Then let's mock it: GeocodingApiRequest geocodingApiRequest = mock(GeocodingApiRequest.class);

之后.模拟所有需要模拟的呼叫:

After. mock all calls that need to be mocked:

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

另一个错误,但和以前一样重要,而且很明显:未为geocodingResult设置必需的文件.

Another mistake, but so important as previous and more obviously: required files isn't set for 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);
    }
}

这篇关于如何使用Mockito/Powermock模拟Google的Geocoding API请求?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

06-26 12:45