【问题标题】:Mockito when().thenReturn() throws nullpointerExceptionsMockito when().thenReturn() 抛出 nullpointerExceptions
【发布时间】:2017-07-21 10:35:20
【问题描述】:

我正在尝试使用 Mockito 创建一个从 Mock 对象返回的 Mock 对象。具体来说,我正在尝试模拟我的程序可以用来检索 IP 地址的PlayerConnection 对象。

你可以找到更多关于这个PlayerConnection objecthere。它返回一个InetSocketAddress,然后可以返回一个InetAddress,它可以返回一个带有播放器IP的String。但我做不到那么远,因为我的第一个when(class.function()).thenReturn(returnVariable) 抛出了一个NullPointerException。这是我的代码:

/**
 * Creates a partial mock of a connection that can return an ip address.
 * 
 * @param String
 *            The IP to return when the connection gets asked.
 * @return
 */
private PlayerConnection newConnection(String ipString)
{
    PlayerConnection playerConnection = mock(PlayerConnection.class);
    InetSocketAddress inetSocketAddress = mock(InetSocketAddress.class);
    InetAddress inetAddress = mock(InetAddress.class);

    when(playerConnection.getAddress()).thenReturn(inetSocketAddress);
    when(inetSocketAddress.getAddress()).thenReturn(inetAddress);
    when(inetAddress.getHostAddress()).thenReturn(ipString);

    return playerConnection;
}

这是堆栈跟踪,发生在when(playerConnection.getAddress()).thenReturn(inetSocketAddress)

Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.001 sec <<< FAILURE!
ruleResponseTest(com.github.heartsemma.communitywall.ConnectionChecks.RuleManagerTest)  Time elapsed: 0.001 sec  <<< ERROR!
java.lang.NullPointerException
        at java.net.InetSocketAddress$InetSocketAddressHolder.access$500(InetSocketAddress.java:56)
        at java.net.InetSocketAddress.getAddress(InetSocketAddress.java:334)
        at com.github.heartsemma.communitywall.ConnectionChecks.RuleManagerTest.newConnection(RuleManagerTest.java:99)
        at com.github.heartsemma.communitywall.ConnectionChecks.RuleManagerTest.ruleResponseTest(RuleManagerTest.java:44)

编辑:

我已将我的存根切换到 doReturn().when().function() 而不是 when().thenReturn() 以停止 NullPointerExceptions,并且确实如此,但现在我从 Mockito 获得了自定义 UnfinishedStubbingExceptions

有用的错误代码表明我在某处有一个未完成的存根,但我看不到它在哪里。错误发生在第二个doReturn() 方法上。

/**
 * Creates a partial mock of a connection that can return an ip address.
 * 
 * @param ipString The IP to return.
 *            
 * @return A PlayerConnection object that can return a Host Address of the ipString but nothing else.
 */
private PlayerConnection newConnection(String ipString)
{
    PlayerConnection playerConnection = mock(PlayerConnection.class);
    InetSocketAddress inetSocketAddress = mock(InetSocketAddress.class);
    InetAddress inetAddress = mock(InetAddress.class);

    doReturn(inetSocketAddress).when(playerConnection).getAddress();
    doReturn(inetAddress).when(inetSocketAddress).getAddress();
    doReturn(ipString).when(inetAddress).getHostAddress();

    return playerConnection;
}

【问题讨论】:

  • 我不明白。你有同样的错误,同样的答案是使用doReturn(inetSocketAddress).when(playerConnection).getAddress(),就像提到的那样,你没有这样做(那么你怎么能说它没有帮助呢?)。
  • 对不起;我的意思是它导致了另一个错误。编辑原始帖子。

标签: java unit-testing mockito


【解决方案1】:

总结: InetSocketAddress.getAddress() 是最终结果,as listed in the docs。由于其巧妙的语法,Mockito 无法轻易地存根或验证final 方法,甚至无法告诉您它何时尝试和失败。一般来说,不要模拟你无法控制的对象,尤其是在这种情况下。

UnfinishedStubbingException 的有用错误代码可以识别您的问题(请参阅选项 #2,您这个顽皮的开发人员!):

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at 

E.g. thenReturn() may be missing.
Examples of correct stubbing:
    when(mock.isOk()).thenReturn(true);
    when(mock.isOk()).thenThrow(exception);
    doThrow(exception).when(mock).someVoidMethod();
Hints:
 1. missing thenReturn()
 2. you are trying to stub a final method, you naughty developer!
 3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed  

详细信息: 传统的 Mockito 模拟通过获取一个对象并自动且静默地生成一个子类来工作,其中所有方法都被覆盖以委托给 Mockito。但是,Java 编译器利用了 final 方法的静态分派,因此对 final 方法的调用不会直接转到 Mockito,而是转到 InetSocketAddress 中的真实方法实现。这个子类实例不打算与之交互,也没有设置任何字段,因此很容易得到 NullPointerException 或其他行为——所有这些都发生在你与 Mockito 交互之前,所以你不要使用 when(object.methodCall()).thenReturn() 时甚至无法从合理的错误消息中获益,因为在 Mockito 完全参与之前评估 object.methodCall() 时会发生意外的 NPE。

以另一种方式做事——doReturn(...).when(object).methodCall()——让 Mockito 有机会看到 doReturnwhen,即使对 methodCall 的调用没有委托给 Mockito。这给了 Mockito 上下文来说明存根未完成,因为 Mockito 看不到 methodCall 调用。

有关详细信息,请参阅此 SO 问题 (Final method mocking) 并考虑使用 Mockito 在 2.1 版中引入的最新 opt-in mocking of final classes and methods

【讨论】:

  • 非常感谢。我没有意识到 InetSocketAddress.getAddress() 是最终的。
  • 好问题,好答案!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-18
  • 2016-01-12
  • 1970-01-01
相关资源
最近更新 更多