【问题标题】:Integration Test with Spring Boot and Spock使用 Spring Boot 和 Spock 进行集成测试
【发布时间】:2014-08-15 20:13:36
【问题描述】:

使用 Spock 运行集成测试(例如,@IntegrationTest)的最佳方式是什么?我想引导整个 Spring Boot 应用程序并执行一些 HTTP 调用来测试整个功能。

我可以用 JUnit 做到这一点(首先应用程序运行,然后执行测试):

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyServer.class)
@WebAppConfiguration
@IntegrationTest
class MyTest {
   RestTemplate template = new TestRestTemplate();

   @Test
   public void testDataRoutingWebSocketToHttp() {
      def a = template.getForEntity("http://localhost:8080", String.class)
      println a
   }
}

但使用 Spock 时应用程序无法启动:

@SpringApplicationConfiguration(classes = MyServer.class)
@WebAppConfiguration
@IntegrationTest
class MyTestSpec extends Specification {

   RestTemplate template = new TestRestTemplate();

   def "Do my test"() {
      setup:
      def a = template.getForEntity("http://localhost:8080", String.class)

      expect:
      println a
   }
}

当然,对于 Spock,我已经在我的 Gradle 构建文件中指定了正确的依赖项:

...
dependencies {
   testCompile 'org.spockframework:spock-core:0.7-groovy-2.0'
   testCompile 'org.spockframework:spock-spring:0.7-groovy-2.0'
}
...

我错过了什么吗?

【问题讨论】:

    标签: java groovy gradle spring-boot spock


    【解决方案1】:

    理想情况下,您将使用 Spring Boot 1.4+ 和 Spock 1.1+。

    Spring Boot 添加了很多有用的注解。除了@ignacio.suay 提到的@SpringBootTest,他们还添加了@TestConfiguration,如果您想在集成测试中使用Spring 模拟而不是Mockito,这将非常有用。

    如果您将 @TestConfiguration 与新的 Spock DetachedMockFactory 结合使用,那么您将拥有将 Spock Mocks 注入 Spring 上下文所需的所有组件。

    我在这里有一篇带有示例代码的博文:Spring Integration Testing with Spock Mocks

    又快又脏就是这个

    @SpringBootTest
    class MyIntegrationTest extends Specification {
    
      @Autowired ExternalRankingService externalRankingServiceMock
    
      def "GetRank"() {
        when:
        classUnderTest.getRankFor('Bob')
    
        then:
        1 * externalRankingServiceMock.fetchRank('Bob') >> 5
    
      }
    
      @TestConfiguration
      static class Config {
        private DetachedMockFactory factory = new DetachedMockFactory()
    
        @Bean
        ExternalRankingService externalRankingService() {
          factory.Mock(ExternalRankingService)
        }
      }
    }
    

    更新 a PR 在 Spock 中获得更多原生支持,用于将 Spock Mocks 注入 Spring 上下文以进行集成测试。新的 @SpringBean@SpringSpy 将类似于 @MockBean@SpyBean 注释

    更新 Spock 1.2 现在应该包含这些更改。在文档更新之前,这里是preview of the Spock 1.2 Annotations for Spring Integration Testing

    【讨论】:

    • TestConfiguration 可用于为测试定义额外的 bean 或自定义,模拟只是众多用例之一。您可以简单地使用 spring @MockBean 来模拟使用 Mockito ....
    • @MariuszS 这个问题是关于 Spock 的。将 Mockito 与 Spock 结合使用会被认为是一种非常糟糕的代码气味。 Spock 内置了嘲弄功能。在给出这个答案时,@MockBean 不支持 Spock Mocks。
    【解决方案2】:

    这是一个启动启动应用程序然后运行 ​​spock 测试的设置:

    class HelloControllerSpec extends Specification {
    
    @Shared
    @AutoCleanup
    ConfigurableApplicationContext context
    
    void setupSpec() {
        Future future = Executors
                .newSingleThreadExecutor().submit(
                new Callable() {
                    @Override
                    public ConfigurableApplicationContext call() throws Exception {
                        return (ConfigurableApplicationContext) SpringApplication
                                .run(Application.class)
                    }
                })
        context = future.get(60, TimeUnit.SECONDS)
    }
    
    void "should return pong from /ping"() {
        when:
        ResponseEntity entity = new RestTemplate().getForEntity("http://localhost:8080/ping", String.class)
    
        then:
        entity.statusCode == HttpStatus.OK
        entity.body == 'pong'
    }
    }
    

    记得在 build.gradle 中添加 spock 和 groovy 的依赖项

    dependencies {
        // other dependencies
        testCompile "org.codehaus.groovy:groovy-all:2.2.0"
        testCompile "org.spockframework:spock-core:0.7-groovy-2.0"
    }
    

    【讨论】:

      【解决方案3】:

      在新的 Spring Boot 版本(1.4)中代替使用:

      @SpringApplicationConfiguration(classes = MyServer.class)
      @WebAppConfiguration
      @IntegrationTest
      

      你可以使用

      @SpringBootTest(classes = MyServer.class)
      

      您将能够启动应用程序上下文并设置任何依赖项。

      有关更多信息,请查看以下示例: http://ignaciosuay.com/how-to-do-integration-tests-with-spring-boot-and-spock/

      【讨论】:

        【解决方案4】:

        问题是 Spock Spring 正在寻找 Spring 的 @ContextConfiguration 注释并且没有设法找到它。严格来说,MyTestSpec @ContextConfiguration 注释,因为它是@SpringApplicationConfiguration 上的元注释,但Spock Spring 不将元注释视为其搜索的一部分。有一个 issue 来解决这个限制。与此同时,您可以解决它。

        @SpringApplicationConfiguration 所做的只是使用特定于引导的上下文加载程序自定义@ContextConfiguration。这意味着您可以通过使用适当配置的@ContextConfiguration 注释来实现相同的效果:

        @ContextConfiguration(loader = SpringApplicationContextLoader.class, classes = MyServer.class)
        @WebAppConfiguration
        @IntegrationTest
        class MyTestSpec extends Specification {
            …
        }
        

        更新:只是为了确保它清楚(并且根据 cmets,它不是),要使其工作,您需要在类路径中包含 org.spockframework:spock-spring

        【讨论】:

        • 很有趣,我很确定我以前尝试过,但没有成功……但无论如何,谢谢!
        • 在启动集成测试时是否有提供 VM 的标志?我已复制此配置,但我的应用程序未启动。我是否正确推断 MyServer 是具有 Configuration 和 EnableAutoConfiguration 注释的类?
        • 不需要任何标志,并且您对 MyServer 的推断是正确的。您可以在此处阅读有关 @ContextConfiguration 的更多信息:docs.spring.io/spring/docs/4.0.x/spring-framework-reference/…。你在类路径上有 spock-spring 吗?
        • 嗨@AndyWilkinson 我只是回来让人们知道spock-spring 在类路径中是必需的,我看到了你的回复。谢谢大佬!
        • 我已更新我的答案以使其更清晰。我还打开了一个问题 (github.com/spring-projects/spring-boot/issues/1234) 来更新 Spring Boot 文档的相关部分 (docs.spring.io/spring-boot/docs/1.1.4.RELEASE/reference/…)
        猜你喜欢
        • 2017-06-28
        • 1970-01-01
        • 2018-02-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-24
        • 2017-03-17
        • 1970-01-01
        • 2020-04-09
        相关资源
        最近更新 更多