Spring Integration Testing with Spock Mocks

We all know it’s important to write tests for our code. Often we write unit tests and mock out the dependencies for the class under test. But eventually there is something we need to test that we need a Spring Context spun up for with beans wired, security applied and properties injected. Even in those scenarios, however, there are times where we have a tricky or slow component that we would rather Mock than rely on a component. This post will cover how we can do that with Spock (or JUnit if that’s your thing).

Spring Integration Testing

Spring has lots of tools to help make integration testing easy and fast. Spring Boot makes things even easier. In Spring Boot 1.4 several improvements were introduced to reduce code, make your tests run faster and make edge cases easier to get around.

@MockBean

One of the nicest features introduced is the @MockBean annotation (as well as a @SpyBean). You can now quickly create Mockito mocks inside your test and have them injected into the Spring Context.
The problem is @MockBean is only supported using JUnit and Mockito. If you’re a fan of Spock, things are not quite as simple.

@TestConfiguration to the Rescue

As part of the Spring Boot 1.4 release, new @TestConfiguration and@TestComponent annotations were added to make it easy to define beans and configurations only intended for tests. This means we could create a mock and use it as a bean within the Spring context!

One caveat to note is how all of this impacts context caching.   Mocks are part of the cache key, so it would be best if you can define a single SpringIntegrationTestsConfiguration annotated with @TestConfiguration so all of your integration tests as a whole run faster.

Injecting Spock Mocks into the Spring Context

DetachedMockFactory

If you want to use Spock mocks, the first thing you’ll need to do is make sure you’re on Spock version 1.1 or higher.  This version introduced the ability to define mocks outside of a Spock Specification via the DetachedMockFactory. You’ll also need to include spock-spring if you don’t already have it.  While you’re bringing new stuff in, check out spock-subjects-collaborators-extension for your unit tests.

Now to put it all together. Once you have everything in place, all we need to do is define our mock as a bean in the TestConfiguration.
Once we have our mock bean defined, which will take the place of our normal primary bean, we can utilize it in our specs by just injecting the bean and using it like normal.
We now have full control over our mock service, so if you wanted to test how things behave when throwing exceptions or returning different values based on inputs, you can do that just as quickly and easily as if you were writing a unit test.

Wrap Up

EasyMock, Groovy Mocks, JMock, etc

The concepts above seem like they could easily be applied to other mocking techniques as long as you have the ability to define the mock outside of a test setup.  If you can define the mock inside a @TestConfiguration class, yet describe the behavior in your tests, then you should be in business.

Source Code

If you want to see how this works in more depth, the code is available on GitHub. The PersonControllerIntTest spins up a Spring context so we can make a MockMvc call to a REST endpoint which pulls data from an h2 database via a Spring Data repo, but the “Rank” data we would normally get from an external service has been mocked.

Test often and prosper!

About the Author

Derek Eskens profile.

Derek Eskens

Principal Technologist

Derek has almost 15 years of client server experience in a broad array of industries. Before getting started in technology, Derek worked in Customer Service for many years. That experience has influenced how he approaches software; for new product development and legacy system rewrites alike, he’ll always be a user advocate striving to make things simplier.

Derek is also a rabid an avid foodie. If you need a restaurant recommendation while in Omaha, feel free to get in touch.

One thought on “Spring Integration Testing with Spock Mocks

  1. Adarsh Ramamurthy says:

    Thanks very much for this. Your blog is the only correct solution that works properly with the current versions of Spring Boot and Spock. However, I ended up creating a base class for such tests and managed to move all the cruft out of the way into the base class. My actual test class is now really clean, concerned with just the test code.

    1. Ganesh says:

      You great – Works perfectly. Exactly what i was looking for. Thank you sir 🙂

  2. Rasmus says:

    Great stuff! Would it be possible to define a method call in the configuration as well? E.g. if the getRank method should return the same for all specifications rather than implementing the method in each specifications setup method/each features then block?

  3. Tom Hall says:

    Or just use @SpringBean ExternalRankingService externalRankingServiceMock = Mock() – (for Spock) instead.

    1. xbeo says:

      Thank you for that advice! Haven’t seen any drawbacks so far using this method.

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Blog Posts
Android Development for iOS Developers
Android development has greatly improved since the early days. Maybe you tried it out when Android development was done in Eclipse, emulators were slow and buggy, and Java was the required language. Things have changed […]
Add a custom object to your Liquibase diff
Adding a custom object to your liquibase diff is a pretty simple two step process. Create an implementation of DatabaseObject Create an implementation of SnapshotGenerator In my case I wanted to add tracking of Stored […]
Keeping Secrets Out of Terraform State
There are many instances where you will want to create resources via Terraform with secrets that you just don’t want anyone to see. These could be IAM credentials, certificates, RDS DB credentials, etc. One problem […]
Validating Terraform Plans using Open Policy Agent
When developing infrastructure as code using terraform, it can be difficult to test and validate changes without executing the code against a real environment. The feedback loop between writing a line of code and understanding […]