Издевательские статические методы с PowerMock и Mockito

Я пытаюсь проверить вызов 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");
    }

}

Здесь тестируемый код:

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) загружен во время тестирования, но почему статический метод полностью не издевается без побочных эффектов?

Update:

Я лучше изолирую проблему. Я добавил тестовый метод в свой тестовый пример, который пытается получить соединение из 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. Как я могу обойти это?

Ответ 1

Изменение значения аннотации @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");
    }
}

Благодаря @Szpak за помощь в решении этой проблемы!