Издевательские статические методы с 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 за помощь в решении этой проблемы!