如何配置springboot以在集成测试期间包装DataSource?

pgr*_*en2 2 spring spring-jdbc spring-boot

我的目标是进行集成测试,确保在查找期间不会发生太多数据库查询.(这有助于我们捕获由于错误的JPA配置导致的n + 1个查询)

我知道数据库连接是正确的,因为测试运行期间没有配置问题,只要测试MyDataSourceWrapperConfiguration中没有包含.但是,一旦添加,就会发生循环依赖.(请参阅下面的错误)我认为@Primary有必要让JPA/JDBC代码使用正确的DataSource实例.

MyDataSourceWrapper是一个自定义类,它跟踪给定事务发生的查询数,但它将实际数据库工作委托给DataSource传入的via构造函数.

错误:

The dependencies of some of the beans in the application context form a cycle:

   org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
???????
|  databaseQueryCounterProxyDataSource defined in me.testsupport.database.MyDataSourceWrapperConfiguration 
?     ?
|  dataSource defined in org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Tomcat
?     ?
|  dataSourceInitializer
???????
Run Code Online (Sandbox Code Playgroud)

我的配置:

@Configuration
public class MyDataSourceWrapperConfiguration {

    @Primary
    @Bean
    DataSource databaseQueryCounterProxyDataSource(final DataSource delegate) {
        return MyDataSourceWrapper(delegate);
    }
}
Run Code Online (Sandbox Code Playgroud)

我的测试:

@ActiveProfiles({ "it" })
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration({ DatabaseConnectionConfiguration.class, DatabaseQueryCounterConfiguration.class })
@EnableAutoConfiguration
public class EngApplicationRepositoryIT {

    @Rule
    public MyDatabaseQueryCounter databaseQueryCounter = new MyDatabaseQueryCounter ();

    @Rule
    public ErrorCollector errorCollector = new ErrorCollector();

    @Autowired
    MyRepository repository;

    @Test
    public void test() {
        this.repository.loadData();
        this.errorCollector.checkThat(this.databaseQueryCounter.getSelectCounts(), is(lessThan(10)));
    }

}
Run Code Online (Sandbox Code Playgroud)

更新:这个原始问题是针对springboot 1.5.然而,接受的答案反映了@rajadilipkolli的答案适用于springboot 2.x

M. *_*num 5

在您的情况下,您将获得2个DataSource实例,这可能不是您想要的.而是使用BeanPostProcessor哪个是为此实际设计的组件.另请参见Spring参考指南.

创建并注册一个BeanPostProcessor包装.

public class DataSourceWrapper implements BeanPostProcessor {

    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        if (bean instanceof DataSource) {
             return new MyDataSourceWrapper((DataSource)bean);
        }
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后只需将其注册为@Bean而不是您的MyDataSourceWrapper.

提示:DataSource您可能对datasource-proxydatasource-assert(已经具有计数器等支持)相结合而不是滚动自己的包装(您可以节省维护自己的组件).