Java 如何模拟 DriverManager.getConnection(...)?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19464975/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to mock DriverManager.getConnection(...)?
提问by Dmitrii Pisarenko
I have a class, which connects to an H2 database and runs several SQL statements.
我有一个类,它连接到 H2 数据库并运行多个 SQL 语句。
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.
我想编写一个单元测试,它验证在该open
方法中DROP TABLE IF EXISTS PERSON
是否执行了某个 SQL 语句 ( )。
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.
但它不起作用 - 而不是模拟连接,DriverManager
返回真实连接。
How can I fix it (make DriverManager
return connection mock in the test) ?
我该如何修复它(DriverManager
在测试中模拟返回连接)?
Here's the pom.xml
of my project, maybe something is wrong there.
这pom.xml
是我的项目,也许那里有问题。
<?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>
采纳答案by Dmitrii Pisarenko
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);
}
}
回答by Tom Anderson
The usual way to do this would be to factor out the connection creation into another class, and inject an instance of that into the class in question. You can then mock that new class.
执行此操作的常用方法是将连接创建分解到另一个类中,并将其实例注入相关类中。然后你可以模拟那个新类。
In your case, something like this:
在你的情况下,是这样的:
public class H2Persistence implements IPersistence {
private final ConnectionFactory connectionFactory;
private Connection conn;
public H2Persistence(ConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
@Override
public void open() {
try {
conn = connectionFactory.createConnection(CONN_TYPE_USER_HOME);
// etc
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
catch (SQLException e) {
e.printStackTrace();
}
}
}
public class ConnectionFactory {
Connection createConnection(String connType) throws SQLException, ClassNotFoundException {
Class.forName("org.h2.Driver");
return DriverManager.getConnection(connType);
}
}
In this particular case, even better would probably be to use the standard JDBC interface DataSource
instead of your own connection factory class:
在这种特殊情况下,最好使用标准 JDBC 接口DataSource
而不是您自己的连接工厂类:
public class H2Persistence implements IPersistence {
private final DataSource dataSource;
private Connection conn;
public H2Persistence(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public void open() {
try {
conn = dataSource.getConnection();
// etc
}
catch (SQLException e) {
e.printStackTrace();
}
}
}