Introducing springmock

java groovy

I’ve been using springboot for some time now, but there was that one thing that bugged me a lot. While writing integration tests with mocks you are forced to use mockito as the mocking library. That’s great and easy to understand if you are not using spock. The problem is that in spock there are better ways to mock stuff…​

tl;dr

I’ve created springmock library which allows to inject spock mocks into spock’s Specification classes. It allows to use spock or mockito as mocks provider. Just add com.pchudzik.springmock:springmock-spock:1.0.0 (or springmock-mockito for mockito) to your dependencies and start using @AutowiredMock and @AutowiredSpy in your tests.

Why?

Because why not :P

Up until now I’ve been using mockito mocks and mockito syntax in spock integration tests. It was the easiest and the most obvious way to work with mocks. Of course there is this ugly workaround which allows to inject spock mocks into specification (thanks to release of DetachedMocks from spock 1.1):

@Configuration
static class Config {
  private final mockFactory = new DetachedMockFactory()

  @Bean
  Service service() {
    mockFactory.Mock(Service.class)
  }
}

But when you look at it there is a lot of boilerplate (and most of it is hidden from you) which is not required when using @MockBean or @SpyBean. Why is spock treated as a second class citizen you might ask? Why are you forced to create 'custom' mocks that way? Why mockito is the only right mocking library to mock stuff?

Lately I’ve got some time off and decided it will be fun to dive into spring source code and see how it’s working and what can I do to inject spock mocks instead of mockito mocks. I suggested that I can refactor it in spring but the idea was rejected and spring guys suggested that it can be pulled out of the spring. Instead of pulling it out as is I decided it will be more educational to figure some of this stuff on my own and that’s exactly what I did. I’ve started developing springmock library for fun and now after some time I have something to show.

To the point

springmock allows to inject mocks and create spies using any mocking library as mocks and spies provider. Right now only spock and mockito are supported. The important thing here is that with springmock you can easily create and inject spock mocks into spock Specification (mockito support is there to prove that the idea of mocks providers might work).

One example will tell more than 1000 words so here is what I’ve got now:

@SpringBootTest
class SpockSamplesApplicationTest extends Specification {
  @AutowiredMock //<1>
  AddOneTranslator addOneTranslator

  @AutowiredSpy  //<2>
  TwoRepository twoRepository

  @MockBean      //<3>
  LogService logService

  @Autowired
  MyService myService

  def "should calculate values"() {
    given:
    final inputA = 1
    final translatedA = 10
    final expectedResult = translatedA + TWO

    addOneTranslator.addOne(inputA) >> translatedA  //<4>

    when:
    final result = myService.calculate(inputA)

    then:
    1 * twoRepository.getTwo()  //<5>
    result == expectedResult

    Mockito.verify(logService).logCall(inputA, expectedResult) // <6>
  }
}
<1> simply use @AutowiredMock which will register bean in the context and inject mock to specification
<2> @AutowiredSpy will locate existing bean in the spring context and replace it with the spy
<3> you can mix springmock annotations with @MockBean and @SpyBean already available in spring-test
<4> configure behavior of spock mock
<5> verify spock spy call
<6> verify mockito mock behavior

What I’ve got is MVP. You can register and inject mocks and you can create spies from already registered objects and that’s all for now. When I’ll have free time I’m going to implement more features like java7 compatibility and additional mocks and spies configuration.

If you are still interested but not yet convinced you can check out:

You don’t need springboot to use springmock. Sample projects are based on springboot because it’s the fastest way to get this running but check out integration tests there is no springboot there.

How to get it

You can try it yourself just add dependency to springmock and you are good to go:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>com.pchudzik.springmock</groupId>
  <artifactId>springmock-mockito</artifactId>
  <version>1.0.0</version>
  <scope>test</scope>
</dependency>

or gralde

testCompile('com.pchudzik.springmock:springmock-spock:1.0.0')
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile('org.spockframework:spock-core:1.1-groovy-2.4')
testCompile('org.spockframework:spock-spring:1.1-groovy-2.4')

If you want latest not yet stable features you can fetch snapshot release.

In both maven and gradle it is your job to provide mockito|spock and spring-test dependencies (spring-boot-starter-tests ships with mockito and spring-test). What’s more, as for right now java8 is a must to use springmock.

To find out latest available version you check out readme file. Remember that you can use it along with spring @MockBean and @SpyBean and you don’t need springboot to use it so you are not forced to refactor all your tests. If you decide to give it a try please let me know about any bugs I’ve missed. Don’t hesitate to request new features there is a good chance that I’ll implement them.

Up to date instructions are always on github. Have fun mocking stuff :)

25 Jul 2017 #java #groovy #spock #spring #springmock