Java Spring启动测试:在嵌套测试中运行脚本(@Sql(";/script.Sql";)

Java Spring启动测试:在嵌套测试中运行脚本(@Sql(";/script.Sql";),java,spring,mockito,integration-testing,junit5,Java,Spring,Mockito,Integration Testing,Junit5,在SpringBoot项目的测试中,我无法在嵌套类中执行SQL脚本 代码 @ExtendWith(SpringExtension.class) @SpringBootTest(classes = SecurityTestConfig.class) @AutoConfigureMockMvc @ActiveProfiles({"test", "test-security-profile"}) @TestInstance(Lifecycle.PER_CLASS) class MyTest{

在SpringBoot项目的测试中,我无法在嵌套类中执行SQL脚本

代码

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = SecurityTestConfig.class)
@AutoConfigureMockMvc
@ActiveProfiles({"test", "test-security-profile"})
@TestInstance(Lifecycle.PER_CLASS)
class MyTest{
    //...
    @Test
    @Sql("/permission.sql")
    void temp() {//here script is executed well}

    @Nested
    @DisplayName("Inner test")
    class InnerTest {
       @Test
       @Sql("/permission.sql")
       void temp() {//here @Sql throws exception}

    }

}
    @Primary
    @Bean(name = "datasource")
    public BasicDataSource dataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(env.getProperty("spring.datasource.dbcp2.driver-class-name"));
        dataSource.setUrl(env.getProperty("spring.datasource.dbcp2.url"));
        dataSource.setUsername(env.getProperty("spring.datasource.dbcp2.username"));
        dataSource.setPassword(env.getProperty("spring.datasource.dbcp2.password"));
        dataSource.setMaxActive(Integer.valueOf(env.getProperty("spring.datasource.dbcp2.max-total")));
        dataSource.setMaxIdle(Integer.valueOf(env.getProperty("spring.datasource.dbcp2.max-idle")));
        dataSource.setInitialSize(Integer.valueOf(env.getProperty("spring.datasource.dbcp2.initial-size")));
        return dataSource;
    }

    @Bean(name = "h2Datasource")
    public BasicDataSource h2DataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(env.getProperty("spring.h2.datasource.driver-class-name"));
        dataSource.setUrl(env.getProperty("spring.h2.datasource.url"));
        dataSource.setUsername(env.getProperty("spring.h2.datasource.username"));
        dataSource.setPassword(env.getProperty("spring.h2.datasource.password"));

        Resource initData = new ClassPathResource("scripts/h2.sql");
        DatabasePopulator databasePopulator = new ResourceDatabasePopulator(initData);
        DatabasePopulatorUtils.execute(databasePopulator, dataSource);

        return dataSource;
    }

    @Primary
    @Bean
    public DataSourceTransactionManager tx(@Qualifier("datasource")BasicDataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    public DataSourceTransactionManager h2tx(@Qualifier("h2Datasource") BasicDataSource h2Datasource) {
        return new DataSourceTransactionManager(h2Datasource);
    }
异常(运行测试时抛出)

下面是application.yml文件:

spring:
  datasource.dbcp2:
    driver-class-name: org.h2.Driver
    username: tester
    password: tester
    url: jdbc:h2:mem:test_pg
    initial-size: 0
    max-total: 12
    max-idle: 12
  h2:
    datasource:
      url: jdbc:h2:mem:test_h2
      username: tester
      password: tester
      driver-class-name: org.h2.Driver
      init-sql: h2.sql
数据源

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = SecurityTestConfig.class)
@AutoConfigureMockMvc
@ActiveProfiles({"test", "test-security-profile"})
@TestInstance(Lifecycle.PER_CLASS)
class MyTest{
    //...
    @Test
    @Sql("/permission.sql")
    void temp() {//here script is executed well}

    @Nested
    @DisplayName("Inner test")
    class InnerTest {
       @Test
       @Sql("/permission.sql")
       void temp() {//here @Sql throws exception}

    }

}
    @Primary
    @Bean(name = "datasource")
    public BasicDataSource dataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(env.getProperty("spring.datasource.dbcp2.driver-class-name"));
        dataSource.setUrl(env.getProperty("spring.datasource.dbcp2.url"));
        dataSource.setUsername(env.getProperty("spring.datasource.dbcp2.username"));
        dataSource.setPassword(env.getProperty("spring.datasource.dbcp2.password"));
        dataSource.setMaxActive(Integer.valueOf(env.getProperty("spring.datasource.dbcp2.max-total")));
        dataSource.setMaxIdle(Integer.valueOf(env.getProperty("spring.datasource.dbcp2.max-idle")));
        dataSource.setInitialSize(Integer.valueOf(env.getProperty("spring.datasource.dbcp2.initial-size")));
        return dataSource;
    }

    @Bean(name = "h2Datasource")
    public BasicDataSource h2DataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(env.getProperty("spring.h2.datasource.driver-class-name"));
        dataSource.setUrl(env.getProperty("spring.h2.datasource.url"));
        dataSource.setUsername(env.getProperty("spring.h2.datasource.username"));
        dataSource.setPassword(env.getProperty("spring.h2.datasource.password"));

        Resource initData = new ClassPathResource("scripts/h2.sql");
        DatabasePopulator databasePopulator = new ResourceDatabasePopulator(initData);
        DatabasePopulatorUtils.execute(databasePopulator, dataSource);

        return dataSource;
    }

    @Primary
    @Bean
    public DataSourceTransactionManager tx(@Qualifier("datasource")BasicDataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    public DataSourceTransactionManager h2tx(@Qualifier("h2Datasource") BasicDataSource h2Datasource) {
        return new DataSourceTransactionManager(h2Datasource);
    }

有人能解释为什么我试图在嵌套测试类中运行脚本时脚本执行失败吗?我可能认为我丢失了一些配置文件。然而,若我将测试方法直接放在MyTest类中,@Sql脚本运行良好

堆栈跟踪中的失败消息提到:

无法为测试上下文执行SQL脚本…:至少提供一个数据源或PlatformTransactionManager

最后一部分让我知道您的
ApplicationContext
没有为您的
@Nested
测试类正确加载

因此,解决方案是将注释从封闭的测试类复制到嵌套的测试类,如下所示

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = SecurityTestConfig.class)
@AutoConfigureMockMvc
@ActiveProfiles({"test", "test-security-profile"})
@TestInstance(Lifecycle.PER_CLASS)
@Nested
@DisplayName("Inner test")
class InnerTest {
   @Test
   @Sql("/permission.sql")
   void temp() {//here @Sql throws exception}

}
必须复制配置的原因是Spring中的注释不是从封闭类继承的


这是Spring TestContext框架的一个已知限制,可能会与一起解决。

有关信息:所有无数据库嵌套测试都能正常工作如果复制
@springbootest
@AutoConfigureMockMvc
,会发生什么情况,和
@ActiveProfiles
对您的
InnerTest
类的逐字声明?FWIW,这种构造似乎对SpringFramework5.1+有效,如下所示:感谢您的清晰解释。我已经试过你的答案了。但是,它会导致另一个异常:
org.springframework.beans.factory.NoSuchBeanDefinitionException:没有类型为“uz.oltinolma.producer.security.mvc.permission.MyTest”的合格bean可用:至少需要1个符合autowire候选条件的bean。依赖项注释:{}
MyTest$InnerTest#temp
中,听起来像是在使用SpringFramework 5.0;然而,5.1中有一个bug修复程序解决了这个问题。我真的不明白发生了什么。但是,经过两天的尝试,导致上述异常的代码运行良好。好笑,嗯)