Mocking static methods with PowerMock and Mockito
java, junit, mockito, powermock, unit-testing
Solution
Changing your `@PrepareForTest` annotation value to `MySQLDatabaseConnectionFactory.class` will resolve this issue.
This annotation tells PowerMock to prepare certain classes for testing. Classes needed to be defined using this annotation are typically those that needs to be byte-code manipulated. This includes final classes, classes with final, private, static.
In this situation PowerMockito have to replace invocation to static method `DriverManager.getConnection` with mocked code. This is done with usage of byte-code manipulation.
Full code
@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");
}
}
Thanks to @Szpak for helping me to resolve this issue!
Problem
I'm trying to verify a call to `java.sql.DriverManager.getConnection` using JUnit, Mockito, and PowerMock. Here's my test case: ``` @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"); } } ``` Here's the code under test: ``` 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); } } } ``` Interestingly enough, this code fails with a `java.sql.SQLException`: ``` java.lang.RuntimeException: java.sql.SQLException: No suitable driver found for jdbc:mysql://myhost:1111/database ``` Now, I could easily just make sure that my SQL driver (MySQL in this case) is loaded at test time, but why isn't the static method completely mocked out without side-effects? Update: I've better isolated the problem. I've added a test method to my test case which tries getting a connection from `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"); } ``` This test actually passes, while the other test still fails. It seems that PowerMock isn't mocking the reference to the class inside of `MySQLDatabaseConnectionFactory`. How can I work around this?