Using Spring-Boot 1.4 testing features with Spock

There was a great blog post over at the spring.io blog a couple of days ago, introducing the new testing improvements coming with Spring-Boot 1.4. I was very intrigued by these new upcoming features, but at the same time kind of sad, that Spock wasn’t mentioned anywhere in the examples (at least you can find some general mentioning about using Spock for testing Spring-Boot applications in the official documentation). In my humble opinion, using Spock to test your Spring-Boot application is a match made in heaven and since I’m a Spring-Boot as well as Spock fan, I thought I just might provide the examples of using Spock alongside the new Spring-Boot 1.4 testing features the original blog post was lacking.

I’ll try to structure this post similar to the original post so you can skip back and forth between the two and checkout the differences in the examples. In order to integrate Spock with Spring (and Spring-Boot) you’ll need this dependency:
'org.spockframework:spock-spring:1.0-groovy-2.4'

The build.gradle config looks like this (there are some additional dependencies for the example project):

Testing without Spring

The original post gave some great advice about unit testing your distinct Spring components: Don’t involve Spring into this! Thanks to the magic of TDD and dependency injection this shouldn’t be a big problem for the main business components of your application (assuming you’ve followed the practices of The Clean Architecture and Hexagonal Architecture). Let’s look at this example of a Spring @Service using some other @Component (there is no implementation difference between @Service and @Component, we’re talking solely semantics here).

I think it’s a shame that many source code examples and tutorials found in the world wide web use artificial and shallow use cases that are as far away from real world usage scenarios as JavaScript is from having a mature build system and so I’ve tried to come up with a useful example application. A friend once told me the process of cooking a sauce hollandaise is a quite difficult one, because you have to monitor the cooking temperature in a very precise fashion. And so this application represents a temperature monitoring system for sauce hollandaise consisting of a HollandaiseTemperatureMonitor service using some Thermometer component.

Test driving the class HollandaiseTemperatureMonitor I’ve come up with the following Spock tests (Since I’m an inhabitant of the part of the world which uses the metric system, all temperature units are in degree Celsius 😉):

This is an example of a pure unit test without involving any Spring dependencies whatsoever. There is still one interesting Spock feature to be found here. We create a Stub Thermometer by simply calling Stub(Thermometer) and instruct this stub to return the givenTemperature afterwards with this line:

thermometer.currentTemperature() >> givenTemperature

If you are somehow unfamiliar with the term Stub here is a great article by Martin Fowler going deep into the differences between Stubs, Mocks, Fakes and so on.

The corresponding production code of HollandaiseTemperatureMonitor that will make this tests pass looks like this:

Integration tests

So far we haven’t seen any of the new Spring-Boot 1.4 testing features, so let’s get to the cool stuff now. When building a Spring-Application I always like to have a really simple smoke test in place, to simply verify that the application starts without errors. This test may look like the following:

Here you can see the new @SpringBootTest annotation at work, which promises to remove all the integration test boiler plate annotations which you needed prior to Spring-Boot 1.4, alas it is not compatible with Spock right now (see this issue). I’ve already submitted a pull request to add Spring-Boot 1.4 compatibility to Spock, but for now we have to use a workaround by explicitly using the @ContextConfiguration annotation:

If Spock finds the @ContextConfiguration on a class, it will assume this is a Spring test and will act accordingly and so this test will pass as expected.

Now let’s move on to the next new testing feature, testing application slices.

Testing Application Slices

Introducing a new use case to our system, we might like to persist some statistic data of our hollandaise cooking process. And what could be a better place to store this data then a relational database? (The answer is nearly everything else, but I wanted some JPA component for the next example and so I had to come up with something…)

Spring-Boot 1.4 introduces some handy shortcuts for integration testing the persistence layer of your application, like the @DataJpaTest annotation. This annotation will instruct Spring to only initialize the components which are needed for the interaction with the persistence (specifically JPA) layer and so we might gain a faster startup time for our integrations tests.

I’ve written a really simply test to demonstrate this feature:

Please note that again I’ve had to add the @ContextConfiguration annotation or else Spock wouldn’t identify the test as a Spring integration test. This is not mentioned in the official documentation and this behavior stems from the same issue as before.

Summary

Okay, that’s it for now. I simply wanted to give some Spock examples for the new Spring-Boot 1.4 testing stuff the original blog post was lacking and I’m quite amused that I’ve discovered some missing Spock support along the way. I hope the proposed workarounds might help someone wondering why this features aren’t working as described inside the documentation. Maybe I’ll try to implement a more stable Spring discovery for the Spock-Spring module in the near future (for now I’m still waiting for my pull request to be merged 😉).

PS:
You can find the source code at GitHub. I’ve also changed to display the source code with the help of the oEmbed Gist Plugin since syntax highlighting and support of markdown code fencing in WordPress was living hell and I couldn’t stand the broken encodings anymore…
I’m still not totally happy with the small column width of the code examples, I think I need to tweak the WordPress theme in order to work better with source code examples.

  • Pingback: This Week in Spring – May 17th, 2016 | Alexius DIAKOGIANNIS()

  • Anbu Sampath

    Great work..

  • Pingback: This Week in Spring – May 17th, 2016 – Technology Up2date()

  • Igor

    Thanks for the great work. One question. Do you know how works @DataJpaTest with 2 data sources?

    • I haven’t tried this yet, I’ll try this out and if I’ll get this to work, my next blog post will be a tutorial about how to achieve this 😉

      • Igor

        wow! Thanks!

        • It seems I’ve got a working example now. Getting the tests with `@DataJpaTest` to work was no problem and really straight forward. My biggest problem was configuring Spring-Data with multiple datasources and entity managers, I hadn’t done this yet 😉

          I’ll write the blog post including code examples soon.

  • Pingback: @DataJpaTest in my Pocket – Groovy-Coder()

  • tlenczyk

    Hi,

    Did you try to mock components when testing spring controllers with @WebMvcTest ?
    There is new annotation @MockBean but this is Mockito and we would like to use Spock…

    • Hi, I haven’t used this annotation yet, but this sounds cool. I’ll try to get this working and would write a blog post once I figured out a good way to do this 😉

      • Have you figured out a way to test controllers at all with @WebMvcTest? @MockBean has issues with my @Service beans since they are groovy classes. I’d rather just use Spock mocks as my Spring bean dependencies. I tried using the new 1.1-rc1 DetachedMockFactory in a config as a desperate attempt but I couldn’t get that working either.

        • I haven’t looked into this issue in detail yet, I think we won’t be able to get this working until this issue in the spock spring integration is fixed:
          https://github.com/spockframework/spock/issues/624

          • Oh, I see that you’ve already commented on the issue. I’d love to hack this feature into Spock, would be quite important for me as well, but I not sure yet if this is easily possible…

          • Lukasz Krawiec

            Can you clarify the status of this? I’ve read the comments on github but some of it went over my head.

            It seems like integration tests like the ones with @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) in spring boot docs are some way off, but there is a clean substitute?

            To clarify I’m looking for a setup where I mock out some bean using spock (just like they do with @MockBean), but continue using TestRestTemplate.

          • Using `@MockBean` is currently not possible with Spock. There are some workarounds and proposed extensions, but I haven’t started to work on it yet. I think the content of this issue is still the most recent information on this topic: https://github.com/spockframework/spock/issues/624

    • This is not working right now btw. See this issue: https://github.com/spockframework/spock/issues/624

  • Giancarlo Orrù

    Hi,
    Thanks for your work!
    I’m trying to write an integration test that uses TestRestTemplate
    I’m using the new org.springframework.boot.test.web.client.TestRestTemplate via

    @Autowired
    private TestRestTemplate restTemplate;

    restTemplate is not initialized and the test fails.
    I also tried to use @RunWith(SpringRunner.class) but it fails with
    java.lang.Exception: No runnable methods
    Can you give some hints?
    Thanks in advance

    • Could you post your source code (gist) or do you have a link? If you use the stable Spock version with @ContextConfiguration Spring integration won’t work, maybe that is your problem (it sounds like the Spring context is not initialized). @RunWith is not working in combination with Spock.

    • MarS

      Hi,
      Thank you for this helpfull post.
      I writing a test with TestRestTemplate too, when i add @ContextConfiguration and @SpringBootTest and lunch the test i have a No test were found message.
      Do you find a solution ?
      Thanks in advance.

      • Can you share the code? Do you use Gradle and IntelliJ?

        • MarS
          • The code looks alright, I can only assume, it might be a problem with your Maven-Groovy compiler settings, or maybe Surefire? Are you able to run other Spock tests inside this project?

          • MarS

            I found a solution here : http://javaeeyyo.blogspot.fr/2016/09/problemas-al-configurar-un-test-con.html
            Thank you for your help.

          • Would you mind sharing your solution in English? I can’t understand the point of the linked blog post 😉

          • MarS

            I’m not speaking or understand Spanish too, but I can try to explain the solution.
            In my project I create different package. The main class with the @SpringBootApplication were in a sub package. Where I launch the test Spring not found the different class because there are in sub-package. Add @SpringBootApplication (scanBasePackages = {“com. example”, “com. example2”}).
            Sorry for my very bad english. x)

  • David Clark

    Thank you for the post. I am basing my integration tests off of this but I am getting an error (detailed better here:http://stackoverflow.com/questions/39472130/spring-boot-integration-fails-to-start-due-to-testresttemplate-and-apache-ssl). I do not have any references to apache SSL but yet every test fails with Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.apache.http.conn.ssl.SSLConnectionSocketFactory

    Do you know what might be causing this?

  • Ronald

    great article if it would work. probably some errors on my side however:gradlew test has errors: in the code
    Condition not satisfied:

    context != null
    | |
    null false

    at com.groovycoder.spockboot.ApplicationSpecWithoutAnnotation.should boot up without errors(ApplicationSpecWithoutAnnotation.groovy:19)

    • Try adding @ContextConfiguration to the test class. I might have tested the code with the Spock Snapshot Version back then.

  • Olga Maciaszek-Sharma

    Thanks for this example. Haven’t added `@ConfigurationContext` with `@SpringBootTest` at first and wasn’t sure what the issue was.