5

我正在尝试使用 mockito 模拟 JDBI 的Query类,但是它无法模拟其基类的方法SqlStatement

当运行下面的代码时,when 语句实际上是在调用基类中的具体实现,并以NullPointerException.

import java.util.Map;

import org.junit.Test;
import org.skife.jdbi.v2.Query;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class TestClass {
    @Test
    public void testBind() {
        Query<Map<String,Object>> mockQuery = mock(Query.class);
        when(mockQuery.bind("xxx", 5)).thenReturn(mockQuery); //this line fails
        //more stuff here
    }
}

我也用 EasyMock 尝试过,得到了相同的结果,它无法模拟这种方法。

更多信息:

  • Mockito 版本是 1.9.5
  • JDBI 版本是 2.4.1(当前与 dropwizard 一起提供的版本)

例外是:

    java.lang.NullPointerException
        at org.skife.jdbi.v2.SQLStatement.bind(SQLStatement.java:434)
        at TestClass.testBind(TestClass.java:17)
            at ....

任何想法如何解决这个问题?

4

2 回答 2

4

bind中的方法SqlStatement是最终的(例如SQLStatement#bind(String, int)),因此您不能使用 Mockito 模拟它们,这是 mockito 目前无法绕过的 JVM(编辑:)的限制。


EDIT2:请注意,正如下面的评论所指出的,对上面写的内容存在一些误解,这需要我澄清一下:

  • JVM 的限制意味着您无法加载标记为具有最终访问权限的类型的子类,您不能覆盖标记为具有最终访问权限的方法,否则您将得到一个 VerifyError。§8.1.1.2 Java 语言规范的最终类 §8.4.3.3 JLS 的最终方法 §4.10 Java 虚拟机规范
  • mockito 无法绕过意味着 Mockito 目前无法克服 final 类或 final 方法来模拟它们,因为此时 Mockito 使用 CGLIB 生成要模拟的类型的子类。但其他框架(如 PowerMock 或 JMockit)可能能够做到这一点,因为它们有其他策略来克服这一点。

你的选择是改变你的设计,这样你就不必存根那些交互,或者你必须使用 PowerMock,它使用类加载器的复杂技巧来重写类字节码(不是我喜欢的方法,尽管 PowerMock 在技术上令人印象深刻)。

希望有帮助。

于 2013-01-09T19:29:28.883 回答
0

尝试

Mockito.doReturn(mockQuery).when(mockQuery).bind("xxx",5);
于 2013-01-09T17:36:58.003 回答