How to start Spring Boot app in Spock Integration Test
Asked Answered
H

4

43

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.

Spring Boot app starts in this working JUnit test (first the app runs and then the tests execute):

@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 (how can I get it to start?):

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

...
dependencies {
   testCompile 'org.spockframework:spock-core:0.7-groovy-2.0'
   testCompile 'org.spockframework:spock-spring:0.7-groovy-2.0'
}
...
Hengelo answered 25/6, 2014 at 10:4 Comment(1)
I confidently give the benefit of the doubt that indeed, "with Spock the application doesn't start". It would be slightly helpful to update here, what detail it is exactly, that reflects that the app didn't start: Does something initialize null? Is there some expected logging (maybe by Spring) or output, that does not print by the end of the test run?Implicatory
B
53

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.

Benempt answered 25/6, 2014 at 14:58 Comment(4)
Is there a flag to provide the VM when launching integration tests? I have copied this configuration and my app is not starting. Am I right in deducing that MyServer is the class having the Configuration and EnableAutoConfiguration annotations?Heathenry
No flags should be necessary and your deduction about MyServer is correct. You can read more about @ContextConfiguration here: docs.spring.io/spring/docs/4.0.x/spring-framework-reference/…. Have you got spock-spring on the classpath?Benempt
Hi @AndyWilkinson I was just coming back to let people know that spock-spring was necessary in the classpath, and I saw your response. Thanks man!Heathenry
I've updated my answer to make it clearer. I've also opened an issue (github.com/spring-projects/spring-boot/issues/1234) to update the relevant section of the Spring Boot documentation (docs.spring.io/spring-boot/docs/1.1.4.RELEASE/reference/…)Benempt
W
9

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 .

Wo answered 18/4, 2017 at 19:18 Comment(2)
TestConfiguration can be used to define additional beans or customizations for a test, mocking is only one of many use cases. You can simply use spring @MockBean to mock using Mockito....Patronizing
@Patronizing This question is about Spock. It would be considered a pretty bad code smell to use Mockito in conjunction with Spock. Spock has mocking build into it. At the time of this answer, @MockBean didn't support Spock Mocks.Wo
W
5

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/

Wheelbase answered 23/1, 2017 at 17:54 Comment(0)
A
1

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"
}
Archuleta answered 19/6, 2017 at 6:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.