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?
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?
Of course you can – and probably will – use Mockito and PowerMock in the same JUnit test at some point of time.
Since static method belongs to the class, there is no way in Mockito to mock static methods.
Step 1: Create a class that contains a private method. We have created class with the name Utility and defined a private method and a public method (that returns the object of private method). Step 2: Create a JUnit test case named PowerMock_test for testing purpose.
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.
@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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With