How to mock DriverManager.getConnection(...)?
26,932
This one works (pay attention to the imports):
import static org.easymock.EasyMock.expect;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.powermock.api.easymock.PowerMock.mockStatic;
import static org.powermock.api.easymock.PowerMock.replay;
@RunWith(PowerMockRunner.class)
@PrepareForTest({DriverManager.class, H2Persistence.class})
public class H2PersistenceTest {
@Test
public void testDropPersonIsCalled() throws SQLException {
final Statement statement = mock(Statement.class);
final Connection connection = mock(Connection.class);
when(connection.createStatement()).thenReturn(statement);
mockStatic(DriverManager.class);
expect(DriverManager.getConnection(H2Persistence.CONN_TYPE_USER_HOME))
.andReturn(connection);
expect(DriverManager.getConnection(null))
.andReturn(null);
replay(DriverManager.class);
final H2Persistence objectUnderTest = new H2Persistence();
objectUnderTest.open();
verify(statement).executeUpdate("DROP TABLE IF EXISTS PERSON");
verify(statement).executeUpdate(H2Persistence.CREATE_TABLE_PERSON);
}
}
Author by
Glory to Russia
Updated on July 05, 2022Comments
-
Glory to Russia almost 2 years
I have a class, which connects to an H2 database and runs several SQL statements.
public class H2Persistence implements IPersistence { private Connection conn; @Override public void open() { try { Class.forName("org.h2.Driver"); conn = DriverManager.getConnection(CONN_TYPE_USER_HOME); final Statement stmt = conn.createStatement(); stmt.executeUpdate("CREATE TABLE PERSON(" + "ID BIGINT,"+ "AGEGROUP VARCHAR(255),"+ "MONTHLY_INCOME_LEVEL VARCHAR(255)," + "GENDER VARCHAR(1),"+ "HOUSEHOLD_ID BIGINT)"); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } ... }
I want to write a unit test, which verifies, that in the
open
method a certain SQL statement (DROP TABLE IF EXISTS PERSON
) is executed.In order to do this, I wrote following test:
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.powermock.api.mockito.PowerMockito.mockStatic; import static org.powermock.api.mockito.PowerMockito.when; @RunWith(PowerMockRunner.class) @PrepareForTest(DriverManager.class) public class H2PersistenceTest { @Test public void testDropPersonIsCalled() throws SQLException { final Statement statement = mock(Statement.class); final Connection connection = mock(Connection.class); when(connection.createStatement()).thenReturn(statement); mockStatic(DriverManager.class); when(DriverManager.getConnection(H2Persistence.CONN_TYPE_USER_HOME)).thenReturn (connection); final H2Persistence objectUnderTest = new H2Persistence(); objectUnderTest.open(); verify(statement.executeUpdate("DROP TABLE IF EXISTS PERSON")); } }
But it doesn't work - instead of the mock connection,
DriverManager
returns real connection.How can I fix it (make
DriverManager
return connection mock in the test) ?Here's the
pom.xml
of my project, maybe something is wrong there.<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>ru.mycompany</groupId> <artifactId>myproduct</artifactId> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <powermock.version>1.5.1</powermock.version> <maven.compiler.source>1.6</maven.compiler.source> <maven.compiler.target>1.6</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> <scope>test</scope> </dependency> <dependency> <groupId>org.easytesting</groupId> <artifactId>fest-util</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.easytesting</groupId> <artifactId>fest-assert-core</artifactId> <version>2.0M8</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>15.0</version> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <version>1.9.5</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>1.3.173</version> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>${powermock.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito</artifactId> <version>${powermock.version}</version> <scope>test</scope> </dependency> </dependencies> </project>
-
Glory to Russia over 10 yearsI've done this before (see altruix.wordpress.com/portfolio/project-control-center for details). The problem is that if you write lots of classes you end up with lots of boilerplate code (interface, factory interfaces and their implementations). So I tried to get the advantage of that design (testability) without the costs (lot of boilerplate code).
-
Tom Anderson over 10 yearsThat is definitely a danger of taking this approach when writing mock-based tests. I work on a codebase where much of the logic has been ground to a fine powder by the millstones of mock-driven refactoring. In this case, given that
DataSource
already exists, represents a well-defined, self-contained concept, and has implementations already, i would think that the risk of boilerplate overgrowth is small.