使用PowerMock和Mockito模拟静态方法

Naf*_*Kay 23 java junit unit-testing mockito powermock

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

这是我的测试用例:

@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");
    }

}
Run Code Online (Sandbox Code Playgroud)

这是测试中的代码:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

java.lang.RuntimeException: java.sql.SQLException: No suitable driver found for jdbc:mysql://myhost:1111/database
Run Code Online (Sandbox Code Playgroud)

现在,我可以很容易地确保我的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");
}
Run Code Online (Sandbox Code Playgroud)

此测试实际通过,而另一个测试仍然失败.似乎PowerMock并没有嘲笑里面的类的引用MySQLDatabaseConnectionFactory.我该如何解决这个问题?

Mar*_*szS 29

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

此注释告诉PowerMock准备某些类以进行测试.需要使用此批注定义的类通常是需要进行字节码操作的类.这包括最终类,最终类,私有类,静态类.

在这种情况下,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");
    }
}
Run Code Online (Sandbox Code Playgroud)

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