我使用Mockito,DBUnit和HSQLDB对我的数据库代码进行单元测试。我当然也在编写集成测试。
我无法理解如何将被模拟的DataSource注入被测系统(I类测试)。 DataSource
用于连接池,因此其他类可以在同一个类中调用static
方法,以便检索此DataSource
的实例。这意味着DataSource
不会在任何地方注入任何构造函数,因此我的测试没有任何构造函数可以将模拟的DataSource
注入其中。
我通过改变我的实际代码的逻辑来检查私有变量是否为null,如果是,那么使用注入的DataSource(设计不好,因为它只需要测试) ,否则它调用静态方法来检索连接池的源(更好的设计)。
如何将一个模拟的DataSource
注入一个没有构造函数设置为接受它的类,因为它可以只调用静态方法来检索依赖项?
要测试的课程
public DBConnection(DBSource dbSource) { // <--- Constructor only required for test purposes :(
this.dbSource = dbSource;
}
public final void createCompsDB() {
Connection conn = null;
Statement statement = null;
try {
if(dbSource==null){
conn = DBSource.getInstance().getConnection();
}else{
conn = dbSource.getConnection(); /** Likely bad design, since dbSource is only NOT null for tests, so that you can inject the mocked datasource :( */
}
statement = conn.createStatement();
statement.executeUpdate("CREATE DATABASE placesdb");
System.out.println("Database created...");
} catch (SQLException e) {
// ...
}
} finally {
// Close Resources...
}
}
}
测试类 - 测试通行证
public class DBConnectionTest {
final Statement statement = mock(Statement.class);
final Connection connection = mock(Connection.class);
final DBSource dataSource = mock(DBSource.class);
@Before
public void setUp() throws SQLException, IOException, PropertyVetoException {
when(dataSource.getConnection()).thenReturn(connection);
when(connection.createStatement()).thenReturn(statement);
}
@Test
public void testCreateCompDBIfNotAlready() throws Exception {
DBConnection dbConnection = new DBConnection(localDB, dataSource); /** This constructor is only needed for testing :( . How do I avoid it since all the classes I need to test don't require the dependency to be injected? */
dbConnection.createCompsDB();
verify(statement).executeUpdate("CREATE DATABASE PLACES");
}
}
DBSource.java
protected DBSource() throws IOException, SQLException, PropertyVetoException {
ds = new BasicDataSource();
ds.setDriverClassName("org.postgresql.Driver");
ds.setUsername("user");
ds.setPassword("pass");
ds.setUrl("jdbc:postgresql://localhost:5432/placesdb");
}
public static DBSource getInstance() { // <--- Static method means dependent classes don't need to accept injections
if (datasource == null) {
datasource = new DBSource();
return datasource;
} else {
return datasource;
}
}
public Connection getConnection() throws SQLException {
return this.ds.getConnection();
}
}
答案 0 :(得分:3)
可以使用PowerMockito完成静态类方法的模拟。 测试类应该是这样的:
@RunWith(PowerMockRunner.class)
@PrepareForTest(DBSource.class)
public class DBConnectionTest {
@Mock
final Statement statement;
@Mock
final Connection connection;
@Mock
final DBSource dbsource;
@Before
public void setUp() throws SQLException, IOException, PropertyVetoException {
PowerMockito.mockStatic(DBSource.class);
when(DbSource.getInstance()).thenReturn(dbsource);
when(dbsource.getConnection()).thenReturn(connection);
when(connection.createStatement()).thenReturn(statement);
}
@Test
public void testCreateCompDBIfNotAlready() throws Exception {
DBConnection dbConnection = new DBConnection(localDB); // No test-only constructor anymore
dbConnection.createCompsDB();
verify(statement).executeUpdate("CREATE DATABASE PLACES");
}
}
您可以阅读here有关使用PowerMock进行模拟的更多信息。