Mocking static methods with PowerMock and Mockito

19,385

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!

Share:
19,385

Related videos on Youtube

Naftuli Kay
Author by

Naftuli Kay

Updated on July 08, 2022

Comments

  • Naftuli Kay
    Naftuli Kay almost 2 years

    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?