如何正确模拟Bean HikariDataSource? [英] How to mock bean HikariDataSource correctly?

查看:16
本文介绍了如何正确模拟Bean HikariDataSource?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Mockito编写了集成测试,但当设置了到数据库的连接时,它可以工作。实际上,测试只是检查访问一些与数据访问层无关的端点的可能性。所以我还不需要它的数据库。 数据库关闭时测试失败的原因--当Spring实例化上下文时,HikariDatasource检查到数据库的连接。模仿不返回连接,导致应用失败。我找到解决方案是在内存数据库中使用hsql,但对我来说,这似乎是一种变通办法。是否存在提供虚假数据的其他解决方案?

推荐答案

我不确定这是否是完美的解决方案,但我需要强制进行这样的工作测试

mockMvc.perform( post("/some").contentType(MediaType.APPLICATION_JSON_UTF8) .content(objectMapper.writeValueAsString(someDto)) .header(HttpHeaders.AUTHORIZATION, AUTH_HEADER) .accept(MediaType.APPLICATION_JSON_UTF8) ).andExpect(status().is(201));

经过调试和搜索,我找到了允许在内存中启动容器而不使用数据库的解决方案。

@TestConfiguration
@ComponentScan(basePackages = "com.test")
@ActiveProfiles("test")
public class TestConfig {
//Other Beans

    @Bean
    public DataSource getDatasource() {
        return new MockDataSource();
    }

}

class MockDataSource implements DataSource {
    @Override
    public Connection getConnection() throws SQLException {
        return createMockConnection();
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return getConnection();
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {
    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {
    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }

    public static Connection createMockConnection() throws SQLException {
        // Setup mock connection
        final Connection mockConnection = mock(Connection.class);

        // Autocommit is always true by default
        when(mockConnection.getAutoCommit()).thenReturn(true);

        // Handle Connection.createStatement()
        Statement statement = mock(Statement.class);
        when(mockConnection.createStatement()).thenReturn(statement);
        when(mockConnection.createStatement(anyInt(), anyInt())).thenReturn(statement);
        when(mockConnection.createStatement(anyInt(), anyInt(), anyInt())).thenReturn(statement);
        when(mockConnection.isValid(anyInt())).thenReturn(true);

        // Handle Connection.prepareStatement()
        PreparedStatement mockPreparedStatement = mock(PreparedStatement.class);
        when(mockConnection.prepareStatement(anyString())).thenReturn(mockPreparedStatement);
        when(mockConnection.prepareStatement(anyString(), anyInt())).thenReturn(mockPreparedStatement);
        when(mockConnection.prepareStatement(anyString(), (int[]) any())).thenReturn(mockPreparedStatement);
        when(mockConnection.prepareStatement(anyString(), (String[]) any())).thenReturn(mockPreparedStatement);
        when(mockConnection.prepareStatement(anyString(), anyInt(), anyInt())).thenReturn(mockPreparedStatement);
        when(mockConnection.prepareStatement(anyString(), anyInt(), anyInt(), anyInt())).thenReturn(mockPreparedStatement);
        doAnswer((Answer<Void>) invocation -> null).doNothing().when(mockPreparedStatement).setInt(anyInt(), anyInt());

        ResultSet mockResultSet = mock(ResultSet.class);
        when(mockPreparedStatement.executeQuery()).thenReturn(mockResultSet);
        when(mockResultSet.getString(anyInt())).thenReturn("aString");
        when(mockResultSet.next()).thenReturn(true);

        // Handle Connection.prepareCall()
        CallableStatement mockCallableStatement = mock(CallableStatement.class);
        when(mockConnection.prepareCall(anyString())).thenReturn(mockCallableStatement);
        when(mockConnection.prepareCall(anyString(), anyInt(), anyInt())).thenReturn(mockCallableStatement);
        when(mockConnection.prepareCall(anyString(), anyInt(), anyInt(), anyInt())).thenReturn(mockCallableStatement);

        ResultSet mockResultSetTypeInfo = mock(ResultSet.class);

        DatabaseMetaData mockDataBaseMetadata = mock(DatabaseMetaData.class);
        when(mockDataBaseMetadata.getDatabaseProductName()).thenReturn("PostgreSQL");
        when(mockDataBaseMetadata.getDatabaseMajorVersion()).thenReturn(8);
        when(mockDataBaseMetadata.getDatabaseMinorVersion()).thenReturn(2);
        when(mockDataBaseMetadata.getConnection()).thenReturn(mockConnection);
        when(mockDataBaseMetadata.getTypeInfo()).thenReturn(mockResultSetTypeInfo);
        when(mockConnection.getMetaData()).thenReturn(mockDataBaseMetadata);


        // Handle Connection.close()
        doAnswer((Answer<Void>) invocation -> null).doThrow(new SQLException("Connection is already closed")).when(mockConnection).close();

        // Handle Connection.commit()
        doAnswer((Answer<Void>) invocation -> null).doThrow(new SQLException("Transaction already committed")).when(mockConnection).commit();

        // Handle Connection.rollback()
        doAnswer((Answer<Void>) invocation -> null).doThrow(new SQLException("Transaction already rolled back")).when(mockConnection).rollback();

        return mockConnection;
    }
}

模拟数据源允许使用MockMvc启动容器并提供对控制器的POST调用。

这篇关于如何正确模拟Bean HikariDataSource?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆