java - Spring启动测试: run script in a nested test (@Sql ("/script.sql"))

标签 java spring mockito integration-testing junit5

在我的 Spring boot 项目的测试中,我无法在嵌套类中执行 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}

    }

}

异常(运行测试时抛出)

java.lang.IllegalStateException: Failed to execute SQL scripts for test context [DefaultTestContext@406ad6d5 testClass = MyTest.InnerTest, testInstance = uz.oltinolma.producer.security.mvc.permission.MyTest$InnerTest@2a7bc16b, testMethod = temp@MyTest.InnerTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@1186374c testClass = MyTest.InnerTest, locations = '{}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@5f8e8a9d, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@3cce5371, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@4f0f2942], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]], attributes = map[[empty]]]: supply at least a DataSource or PlatformTransactionManager.
    at org.springframework.util.Assert.state(Assert.java:94) ~[spring-core-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener.executeSqlScripts(SqlScriptsTestExecutionListener.java:203) ~[spring-test-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener.executeSqlScripts(SqlScriptsTestExecutionListener.java:142) ~[spring-test-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener.beforeTestMethod(SqlScriptsTestExecutionListener.java:112) ~[spring-test-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:291) ~[spring-test-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.test.context.junit.jupiter.SpringExtension.beforeEach(SpringExtension.java:107) ~[spring-test-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeBeforeEachCallbacks$0(TestMethodTestDescriptor.java:129) ~[junit-jupiter-engine-5.1.0.jar:5.1.0]
    at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40) ~[junit-jupiter-engine-5.1.0.jar:5.1.0]
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeMethodsOrCallbacksUntilExceptionOccurs(TestMethodTestDescriptor.java:155) ~[junit-jupiter-engine-5.1.0.jar:5.1.0]
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeEachCallbacks(TestMethodTestDescriptor.java:128) ~[junit-jupiter-engine-5.1.0.jar:5.1.0]
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:107) ~[junit-jupiter-engine-5.1.0.jar:5.1.0]
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:58) ~[junit-jupiter-engine-5.1.0.jar:5.1.0]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:112) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) ~[?:1.8.0_131]
    at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175) ~[?:1.8.0_131]
    at java.util.Iterator.forEachRemaining(Iterator.java:116) ~[?:1.8.0_131]
    at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801) ~[?:1.8.0_131]
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[?:1.8.0_131]
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[?:1.8.0_131]
    at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) ~[?:1.8.0_131]
    at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) ~[?:1.8.0_131]
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:1.8.0_131]
    at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418) ~[?:1.8.0_131]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) ~[?:1.8.0_131]
    at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175) ~[?:1.8.0_131]
    at java.util.Iterator.forEachRemaining(Iterator.java:116) ~[?:1.8.0_131]
    at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801) ~[?:1.8.0_131]
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[?:1.8.0_131]
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[?:1.8.0_131]
    at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) ~[?:1.8.0_131]
    at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) ~[?:1.8.0_131]
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:1.8.0_131]
    at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418) ~[?:1.8.0_131]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) ~[?:1.8.0_131]
    at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175) ~[?:1.8.0_131]
    at java.util.Iterator.forEachRemaining(Iterator.java:116) ~[?:1.8.0_131]
    at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801) ~[?:1.8.0_131]
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[?:1.8.0_131]
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[?:1.8.0_131]
    at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) ~[?:1.8.0_131]
    at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) ~[?:1.8.0_131]
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:1.8.0_131]
    at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418) ~[?:1.8.0_131]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) ~[?:1.8.0_131]
    at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175) ~[?:1.8.0_131]
    at java.util.Iterator.forEachRemaining(Iterator.java:116) ~[?:1.8.0_131]
    at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801) ~[?:1.8.0_131]
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[?:1.8.0_131]
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[?:1.8.0_131]
    at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) ~[?:1.8.0_131]
    at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) ~[?:1.8.0_131]
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:1.8.0_131]
    at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418) ~[?:1.8.0_131]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:55) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:43) ~[junit-platform-engine-1.1.1.jar:1.1.1]
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:220) ~[junit-platform-launcher-1.3.1.jar:1.3.1]
    at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:188) ~[junit-platform-launcher-1.3.1.jar:1.3.1]
    at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:202) [junit-platform-launcher-1.3.1.jar:1.3.1]
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:181) [junit-platform-launcher-1.3.1.jar:1.3.1]
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128) [junit-platform-launcher-1.3.1.jar:1.3.1]
    at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:65) [junit5-rt.jar:?]
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) [junit-rt.jar:?]
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) [junit-rt.jar:?]
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) [junit-rt.jar:?]

下面我给出了 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

数据源

    @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 脚本可以很好地工作。

最佳答案

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

Failed to execute SQL scripts for test context ...: supply at least a DataSource or 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 框架的一个已知限制,可能会与 SPR-15366 一起解决。 .

关于java - Spring启动测试: run script in a nested test (@Sql ("/script.sql")),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53236807/

相关文章:

java - 单元测试模拟服务实现

java - POI 失败 java.lang.LinkageError : loader constraint violation in interface itable initialization

java - application.properties 中的 SpringBoot 未知属性

java - 强制 Spring 的 MBeanExporter 使用特定的 MBeanServer

java - 使用 EvaluationContextExtensionSupport 和自定义 PermissionEvaluator 将 Spring Boot 2.0.6 迁移到 2.1.0 时出现“无效的 bean 定义”

android - Retrofit 中的单元测试以进行回调

java - Glassfish/Hibernate 的 PermGen 空间问题

java - 获取 Maven 编译错误无法执行目标 org.apache.maven.plugins

java - 数字自签名认证更新到期日期

java - 在不更改 src 代码的情况下在 Java 中模拟 Date()