使用Mockito测试接口方法

4

我正在编写一个JUnit测试用例,针对一个内部通过接口调用另一个方法的方法。我正在使用Mockito来模拟这个接口,但出现了NullPointerException异常。我进行了调试,但还没有找到解决办法。getAllVendors()方法会抛出异常,该异常来自一个接口。

MUT

public void prepare() throws AccountServiceException, ManagerException {
vendors = getVendorManager().getAllVendors();

microsites = new ArrayList<VendorMicrositeTO>();
microsites.add( new VendorMicrositeTO( "http://www.docusign.com", "docuSign" ) );

clientUser = createClientUserObject();

}

JUnit

@Test
public void testPrepare() throws Exception {
    AccountAction accountAction = new AccountAction();
    Map<String, Object> actionMap = new HashMap<>();
    actionMap.put("application", "ESignatureIntegrationAction");

    ActionContext.setContext(new ActionContext(actionMap));
    String beanName = Constants.VENDOR_MANAGER_SPRING_BEAN;
    PowerMockito.mockStatic(AppContext.class);
    PowerMockito.when(AppContext.containsBean( beanName )).thenReturn( true );

    IVendorDto iVendorDto = new VendorDto();
    iVendorDto.setActive(true);
    iVendorDto.setCreatedBy("9/15/2016");
    iVendorDto.setName("CorpESignClientUser");
    iVendorDto.setCreatedBy("SYSTEM");

    List<IVendorDto> vendorList = new ArrayList<>();
    vendorList.add(iVendorDto);

    IVendorManager iManager = Mockito.mock((IVendorManager.class));
    Mockito.when(iManager.getAllVendors()).thenReturn(vendorList);

    accountAction.setVendors(vendorList);
    accountAction.prepare();
}

堆栈跟踪

java.lang.NullPointerException
at com.mercuryinsurance.esignature.ui.webapp.action.AccountAction.prepare(AccountAction.java:65)
at test.com.mercuryinsurance.esignature.ui.webapp.action.TestAccountAction.testPrepare(TestAccountAction.java:58)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:66)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:310)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:86)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:94)
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:84)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
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.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

Thanks, in advance

2个回答

1
似乎您在测试中忘记添加一行代码,类似于:


accountAction.setVendorManager(iManager);

抱歉,IManager 没有 setter。 - Jaykumar
@Jaykumar:根据解决方案的精神,这是正确的。不过你需要提供getVendorManager将会提供的值,否则它会愉快地返回null - Makoto
我正在获取vendorManager,但在调试时它经过了getVendorManager,但由于某种原因它没有进入getAllVendors()。 - Jaykumar

1

嗯,我一直在解决非常类似的问题。

这种用例是在基于物联网的应用程序中应用SOLID原则的逻辑结果。如果你使用接口解耦应用程序的层,并测试内部层,那么你必须测试一个具有更多接口依赖项实现的接口。

您可以通过结合两个测试角度来实现此目标

  1. 使用Parameterized JUnit运行器启动一组单元测试,以针对所有实现进行测试。
  2. 然后在每次运行期间使用Mockito初始化模拟依赖项

有关参数化测试的更多信息(这就是我最初找到它的地方),请确保访问此帖子。手动初始化mockito是我在这里找到的。

总之,生成的代码如下:

 @RunWith(Parameterized.class)
 public class YourInterfaceTest {

   @Mock
   private ImplementationDependency sneakyBreakyNpeAvoided;

   @InjectMocks
   private YourInterfaceToTest iface;
   
   // constructor is used by the Parameterized runner to provide impelementations
   public YourInterfaceTest (YourInterfaceToTest ifaceToTest) {
       this.iface = ifaceToTest;
   }

   // this method is called always before running tests so a good time to inject anything
   @Before
   public void init() {
      MockitoAnnotations.initMocks(this);
      Mockito.when(sneakyBreakyNpeAvoided.returnTrue()).thenReturn(true);
   }

   @Test(expected = IllegalArgumentException.class)
   public void doSomething_nullParameter_throwsIllegalArgumentException() {
      Assert.fail(); // tests here :)
   }

   @Parameterized.Parameters
   public static Collection<YourInterfaceToTest > provideImplementations() {
      // change to Arrays.asList when multiple implementations are available
      return Collections.singletonList(new YourInterfaceImpl());
   }
}

希望我理解了OP的问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接