Integration Test with Spring Boot and Spock

微笑、不失礼 提交于 2019-11-26 15:28:04

问题


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.

I can do it with JUnit (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:

@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'
}
...

Am I missing something?


回答1:


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.




回答2:


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 .




回答3:


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/




回答4:


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"
}


来源:https://stackoverflow.com/questions/24405727/integration-test-with-spring-boot-and-spock

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!