Java 使用 Spring Boot 和 Spock 进行集成测试

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24405727/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 12:02:07  来源:igfitidea点击:

Integration Test with Spring Boot and Spock

javagroovygradlespring-bootspock

提问by kuceram

What is the best way to run an integration test (e.g., @IntegrationTest) with Spock? I would like to bootstrap the whole Spring Boot application and execute some HTTP calls to test the whole functionality.

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

I can do it with JUnit (first the app runs and then the tests execute):

我可以使用 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
   }
}

But with Spock the application doesn't start:

但是使用 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
   }
}

For Spock, of course, I have specified the proper dependencies in my Gradle build file:

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

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

Am I missing something?

我错过了什么吗?

采纳答案by Andy Wilkinson

The problem is that Spock Spring is looking for Spring's @ContextConfigurationannotation and doesn't manage to find it. Strictly speaking MyTestSpecisannotated with @ContextConfigurationas it's a meta-annotation on @SpringApplicationConfigurationbut Spock Spring doesn't consider meta-annotations as part of its search. There's an issueto address this limitation. In the meantime you can work around it.

问题是 Spock Spring 正在寻找 Spring 的@ContextConfiguration注解并且没有设法找到它。严格来说MyTestSpec注解,@ContextConfiguration因为它是元注解,@SpringApplicationConfiguration但 Spock Spring 不考虑元注解作为其搜索的一部分。有一个问题需要解决这个限制。在此期间,您可以解决它。

All that @SpringApplicationConfigurationis doing is customising @ContextConfigurationwith a Boot-specific context loader. This means that you can achieve the same effect by using an appropriately configured @ContextConfigurationannotation instead:

所有这一切@SpringApplicationConfiguration正在做的是定制@ContextConfiguration了引导特定的上下文加载。这意味着您可以通过使用适当配置的@ContextConfiguration注释来实现相同的效果:

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

Update:Just to make sure it's clear (and based on the comments, it wasn't), for this to work you need to have org.spockframework:spock-springon the classpath.

更新:只是为了确保它很清楚(并且根据评论,它不是),为此您需要org.spockframework:spock-spring在类路径上工作。

回答by ignacio.suay

In the new Spring Boot version (1.4) instead of using:

在新的 Spring Boot 版本 (1.4) 中而不是使用:

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

You could use

你可以用

@SpringBootTest(classes = MyServer.class)

and you will be able to start the application context and set any dependency.

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

for further information, please have a look to this example: http://ignaciosuay.com/how-to-do-integration-tests-with-spring-boot-and-spock/

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

回答by Snekse

Ideally you'll use Spring Boot 1.4+ and Spock 1.1+.

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

Spring Boot added a lot of useful annotations. In addition to that @SpringBootTestthat @ignacio.suay mentioned, they also added @TestConfigurationwhich is useful if you want to use Spring mocks in your integration tests instead of Mockito.

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

If you combine @TestConfigurationwith the new Spock DetachedMockFactory, then you have all of the components you'll need to inject Spock Mocks into your Spring context.

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

I have a blog post with sample code here: Spring Integration Testing with Spock Mocks.

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

The quick and dirty is this

又快又脏的是这个

@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)
    }
  }
}

UPDATEThere is a PRto get more native support in Spock for injecting Spock Mocks into the Spring context for integration testing. The new @SpringBeanand @SpringSpywould be like the @MockBeanand @SpyBeanannotations

更新一个 PR可以在 Spock 中获得更多原生支持,用于将 Spock Mocks 注入 Spring 上下文以进行集成测试。新的@SpringBeanand@SpringSpy会像@MockBeanand@SpyBean注释

UPDATESpock 1.2 should now include these changes. Until the documentation is updated, here is a preview of the Spock 1.2 Annotations for Spring Integration Testing.

更新Spock 1.2 现在应该包括这些更改。在文档更新之前,这里是Spock 1.2 Annotations for Spring Integration Testing预览

回答by Marcin Szymczak

Here is a setup which starts up boot applicaiton and then runs spock tests:

这是一个启动引导应用程序然后运行 ​​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'
}
}

And remember to add dependencies to spock and groovy inside build.gradle

并且记得在里面添加对 spock 和 groovy 的依赖 build.gradle

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