Integration Test with Spring Boot and Spock

后端 未结 4 1758
天涯浪人
天涯浪人 2020-12-02 11:10

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

相关标签:
4条回答
  • 2020-12-02 11:43

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

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

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

    I have a blog post with sample code here: 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)
        }
      }
    }
    

    UPDATE There is a PR to get more native support in Spock for injecting Spock Mocks into the Spring context for integration testing. The new @SpringBean and @SpringSpy would be like the @MockBean and @SpyBean annotations

    UPDATE Spock 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 .

    0 讨论(0)
  • 2020-12-02 11:55

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

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

    @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-spring on the classpath.

    0 讨论(0)
  • 2020-12-02 12:01

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

    @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/

    0 讨论(0)
  • 2020-12-02 12:10

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

    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

    dependencies {
        // other dependencies
        testCompile "org.codehaus.groovy:groovy-all:2.2.0"
        testCompile "org.spockframework:spock-core:0.7-groovy-2.0"
    }
    
    0 讨论(0)
提交回复
热议问题