Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Integration Test with Spring Boot and Spock

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?

like image 723
kuceram Avatar asked Jun 25 '14 10:06

kuceram


People also ask

What is Spock in spring boot?

Spock 1.2 adds support for exporting mocks from a Specification into an ApplicationContext . This was inspired by Spring Boot's @MockBean (realised via Mockito) but adapted to fit into Spock style. It does not require any Spring Boot dependencies, however it requires Spring Framework 4.3.

How do you run integration test cases in spring boot?

As explained above, for integrating testing of a spring-boot application, we need to use @SpringBootTest. spring-boot also does provide other classes like TestRestTemplate to test the REST APIs. Like RestTemplate class, it also does have methods getForObject(), postForObject(), exchange(), etc..

Is Spock better than JUnit?

As we can see, Spock has more readability and a clearer documented code, it does not need 3rd parties, and it is more powerful than JUnit. In the end, using Spock or JUnit or TestNG or anything else is absolutely up to you. They each have their pros and cons for sure.

Is SpringBootTest integration test?

Spring boot provides @SpringBootTest annotation which starts the embedded server, creates a web environment and then enables @Test methods to do integration testing. Use it's webEnvironment attribute for it. It also creates the ApplicationContext used in our tests.


2 Answers

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.

like image 165
Andy Wilkinson Avatar answered Sep 22 '22 10:09

Andy Wilkinson


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 .

like image 34
Snekse Avatar answered Sep 20 '22 10:09

Snekse