【问题标题】:Mocking static methods with PowerMock and Mockito使用 PowerMock 和 Mockito 模拟静态方法
【发布时间】:2014-02-03 09:45:27
【问题描述】:

我正在尝试使用 JUnit、Mockito 和 PowerMock 验证对 java.sql.DriverManager.getConnection 的调用。

这是我的测试用例:

@RunWith(PowerMockRunner.class)
@PrepareForTest(DriverManager.class)
public class MySQLDatabaseConnectionFactoryTest {

    private ConfigurationService configurationService;
    private MySQLDatabaseConnectionFactory reference;

    @Before
    public void setUp() throws Exception {
        this.reference = new MySQLDatabaseConnectionFactory();
    }

    @Test
    public void testGetConnection() throws SQLException {
//      setup
        Connection connection = mock(Connection.class);

        PowerMockito.mockStatic(DriverManager.class);

        when(DriverManager.getConnection(anyString(), anyString(), anyString())).thenReturn(connection);

//      run
        this.reference.getConnection();

//      verify
        PowerMockito.verifyStatic();
        DriverManager.getConnection("jdbc:mysql://myhost:1111/database", "username", "password");
    }

}

下面是测试代码:

public class MySQLDatabaseConnectionFactory implements
        DatabaseConnectionFactory {

    @Override
    public Connection getConnection(IApplicationInstance appInstance) {         
        try {
            return DriverManager.getConnection(String.format("jdbc:mysql://%s:%d/%s", 
                    MYSQL_HOST, MYSQL_PORT, MYSQL_DATABASE), MYSQL_USERNAME, MYSQL_PASSWORD);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

有趣的是,这段代码以java.sql.SQLException 失败:

java.lang.RuntimeException: java.sql.SQLException: No suitable driver found for jdbc:mysql://myhost:1111/database

现在,我可以轻松地确保我的 SQL 驱动程序(在本例中为 MySQL)在测试时已加载,但为什么没有完全模拟出静态方法而没有副作用?

更新:

我最好隔离问题。我在我的测试用例中添加了一个测试方法,它尝试从DriverManager 获取连接:

@Test
public void testSomething() {
    Connection conn = mock(Connection.class);
    mockStatic(DriverManager.class);
    when(DriverManager.getConnection(anyString())).thenReturn(conn);
    Connection c = DriverManager.getConnection("whut");
    verifyStatic();
    DriverManager.getConnection("whut");
}

这个测试实际上通过了,而另一个测试仍然失败。似乎 PowerMock 并没有嘲笑对 MySQLDatabaseConnectionFactory 内部类的引用。我该如何解决这个问题?

【问题讨论】:

  • 你在测试中调用了this.reference.getConnection();,但是这个public Connection getConnection(IApplicationInstance appInstance)。你能澄清一下吗?

标签: java unit-testing junit mockito powermock


【解决方案1】:

将您的 @PrepareForTest 注释值更改为 MySQLDatabaseConnectionFactory.class 将解决此问题。

此注释告诉 PowerMock 准备某些类进行测试。需要使用此注解定义的类通常是那些需要字节码操作的类。这包括 final 类,具有 final、private、static 的类。

在这种情况下,PowerMockito 必须用模拟代码替换对静态方法 DriverManager.getConnection 的调用。这是通过使用字节码操作来完成的。

完整代码

@RunWith(PowerMockRunner.class)
@PrepareForTest(MySQLDatabaseConnectionFactory.class)
public class MySQLDatabaseConnectionFactoryTest {

    private MySQLDatabaseConnectionFactory reference;

    @Before
    public void setUp() throws Exception {
        reference = new MySQLDatabaseConnectionFactory();
    }

    @Test
    public void testGetConnection() throws SQLException {

        // given
        PowerMockito.mockStatic(DriverManager.class);
        BDDMockito.given(DriverManager.getConnection(anyString(), anyString(), anyString()))
             .willReturn(mock(Connection.class));

        // when
        reference.getConnection();

        // then
        PowerMockito.verifyStatic();
        DriverManager.getConnection("jdbc:mysql://myhost:1111/database", "username", "password");
    }
}

感谢@Szpak 帮助我解决了这个问题!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-04
    • 1970-01-01
    • 2014-08-30
    • 2014-02-02
    相关资源
    最近更新 更多