【问题标题】:Mockito: No such instance methodMockito:没有这样的实例方法
【发布时间】:2017-11-25 13:09:42
【问题描述】:

我正在为以下给定方法编写测试用例。

方法:

@Override
public void removeAllConnections(String uuid, String userName, String oimId) {
    customLogger.debug(Thread.currentThread().getStackTrace()[1].getMethodName(), userName, null, null, accessProviderBuilder.getUserName(), accessProviderBuilder.getUuid());

    UserAccessBean userAccessBean = new UserAccessBean(userName);
    userAccessBean.setOimid(oimId);
    userAccessBean.setToken("");
    log.info("removeAllConnections:oimid:"+userAccessBean.getOimId());
    UserProfileDetailBean userProfileDetail = accessClient.getAccess(userAccessBean,applicationForCsr);
    Set<AccountAccess> accountAccesses = userProfileDetail.getAccountAccessList();
    try {
        removeAllConnectionsExceptPrimary(oimId, userName, accountAccesses);
        removePrimaryConnection(oimId, userName, accountAccesses);
    } catch (ConnectionStateException e) {
        throw new ConnectionStateException(ConnectionNameNotRemoved, CONNECTION_REMOVAL_FAILED_MSG);
    } catch (InternalServerErrorException e) {
        throw new InternalServerErrorException(INTERNAL_SERVER_ERROR, INTERNAL_SERVER_ERROR_MSG);
    }
}

sn-p 下面是给定方法的测试用例。

测试用例:

@Test
public void testRemoveAllConnections() {
    UserAccessBean userAccessBean = new UserAccessBean(userName);
    when(accessClient.getAccess(userAccessBean,"CSR")).thenReturn(userProfileDetail);
    when(userProfileDetail.getAccountAccessList()).thenReturn(accountAccesses);
    String applicaionForCSR = "CSR";
    ReflectionTestUtils.setField(service, "applicationForCsr", applicaionForCSR);

    service.removeAllConnections(uuid, userName, oimId);

}

在调试代码时,由于 userProfileDetail 的值为 null,我的执行在给定行下方失败。

Set<AccountAccess> accountAccesses = userProfileDetail.getAccountAccessList();

accessClient.getAccess(userAccessBean,applicationForCsr) 上执行检查元素时,它会抛出以下错误。很确定这是一个愚蠢的错误,但无法追踪。

错误:

没有这样的实例方法:'UserProfileDetailBean v1.AccessService$$EnhancerByMockitoWithCGLIB$$a852895d.getAccess (UserAccessBean)'

应用程序:Spring Boot 1.5.0 库:Mockito 2.7.X

【问题讨论】:

  • 请阅读minimal reproducible example 并相应地增强您的问题。你不认为如何声明/注入 null 变量很重要吗?
  • 感谢您的建议,但 null 值本身就是我的问题的一部分。输入总是受欢迎的,
  • 在您的 removeAllConnections 方法中创建的 UserAccessBean 和在您的测试方法中创建的 UserAccessBean 很可能不相等。因此,模拟 accessClient.getAccess() 方法为 removeAllConnections 方法中创建的 UserAccessBean 返回 null。为了更好地解释,你基本上在做,在你的测试中,when(accessClient.getAccess(user1) ...,而在代码中,有一个对accessClient.getAccess(someOtherDifferentUser, ...)的调用。
  • @JBNizet 确认,两个地方的值是一样的。
  • 如何确认?贴出你执行的代码,证明两个 UserAccessBean 实例是相等的。

标签: java intellij-idea junit mockito testcase


【解决方案1】:

我可以提出三种可能的解决方案(或更类似于 2.5):

a) 覆盖UserAccessBeanequals 方法,使得两个UserAccessBeans 相等当且仅当它们的names 相等。当然,这可能会干扰您的生产代码,并且我不会仅仅为了测试而更改 equals 方法。

b) 由于用户名在您的测试中实际上并没有起到至关重要的作用(测试本身定义了用户名是什么),您可以简单地忽略细节...

when(accessClient.getAccess(Mockito.any(UserAccessBean.class),Mockito.eq("CSR"))).thenReturn(userProfileDetail);

这样,对于第一个参数的任何值,都会返回 userProfileDetail。当然,您在这里会丢失细节,例如,如果用户名不正确,则测试将是正确的,但很可能在您的测试中无论如何都是不可能的。

Mockito.any(...) 是一个所谓的 matcher,它告诉 Mockito “使用”此规则,无论为相关参数提供什么值。你放在那里的任何东西都可以用于 Mockito。 Mockito.eq("CSR") 告诉它,这个参数必须等于“CSR”。所以,整个规则是......

如果有人调用accessClient.getAccess,不管第一个参数是什么,但第二个必须等于“CSR”,则返回userProfileDetail

所以,有了这个,第一个参数可以是任何东西。因此,例如,将接受以下调用:

accessClient.getAccess(new UserAccessBean("correct name"), "CSR");
accessClient.getAccess(new UserAccessBean("totally wrong name"), "CSR");

...因为第一个参数是什么都没有关系,任何值都将被接受。因此,您“失去”的是能够检查UserAccessBean 是否正确(因为任何被接受)。但在你的情况下,因为你只在测试中定义了那些UserAccessBeans,所以这应该不是问题。

但如果是,我可以提供两种解决方法...

c) 使用客户匹配器(检查 UserAccessBean 的名称)或使用上面的 Mockito.any(...) 和 ArgumentCaptor 来检查名称是否正确...

ArgumentCaptor<UserAccessBean> captor = ArgumentCaptor.forClass(UserAccessBean.class);
Mockito.verify(accessClient).getAccess(captor.capture(),Mockito.eq("CSR"));
assertEquals(captor.getValue().getName(), "myName");

【讨论】:

  • ...和“B”工作。太感谢了。 :) 但不高兴因为不明白它是如何工作的。你能解释一下吗? “例如,如果用户名错误,测试将是正确的”
  • 我更详细地更新了答案,也许它会有所帮助。如果没有,请随时要求澄清。
猜你喜欢
  • 2014-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多