Posts Tagged ‘springockito’

Discover how to automatically inject Spock’s mocks and spies into the Spring context using Spock 1.2.

Coffee beans with 3 different beans

Stubs/mocks/spies in Spock (and their life cycle) have been always tightly coupled with the Spock Specification class. It was only possible to create them in a test class. Therefore, using shared, predefined mocks (in both unit and integration tests) was problematic.

The situation was slightly improved in Spock 1.1, but only with the brand new Spock 1.2 (1.2-RC1 as a time of writing) using the Spock mocking subsystem in Spring-based integration tests is as easy as using @SpringMock for Mockito mocks in Spring Boot. Let’s check it up.

Btw, to be more cutting edge in addition to Spock 1.2-RC1, I will be using Spring Boot 2.1.0.M2, Spring 5.1.0.RC2 and Groovy 2.5.2 (but everything should work with the stable versions of Spring (Boot) and Groovy 2.4).

One more thing. For the sake of simplicity, in this article, I will be using a term ‘mock’ to refer also stubs and spies. They differs in behavior, however, in a scope of injecting it into the Spring context in the Spock tests it usually doesn’t matter.

Spock 1.1 – manual way

Thanks to the work of Leonard Brünings, mocks in Spock were decoupled from the Specification class. It was finally possible to create them outside and to attach it later on into a running test. It was the cornerstone of using Spock mocks in the Spring (or any other) context.

In this sample code we have the ShipDatabase class which uses OwnShipIndex and EnemyShipIndex (of course injected by a constructor :) ) to return aggregated information about all known ships matched by name.

//@ContextConfiguration just for simplification, @(Test)Configuration is usually more convenient for Spring Boot tests
//Real beans can exist in the context or not
@ContextConfiguration(classes = [ShipDatabase, TestConfig/*, OwnShipIndex, EnemyShipIndex*/])
class ShipDatabase11ITSpec extends Specification {

    private static final String ENTERPRISE_D = "USS Enterprise (NCC-1701-D)"
    private static final String BORTAS_ENTERA = "IKS Bortas Entera"

    @Autowired
    private OwnShipIndex ownShipIndexMock

    @Autowired
    private EnemyShipIndex enemyShipIndexMock

    @Autowired
    private ShipDatabase shipDatabase

    def "should find ship in both indexes"() {
        given:
            ownShipIndexMock.findByName("Enter") >> [ENTERPRISE_D]
            enemyShipIndexMock.findByName("Enter") >> [BORTAS_ENTERA]
        when:
            List<String> foundShips = shipDatabase.findByName("Enter")
        then:
            foundShips == [ENTERPRISE_D, BORTAS_ENTERA]
    }

    static class TestConfig {
        private DetachedMockFactory detachedMockFactory = new DetachedMockFactory()

        @Bean
        @Primary    //if needed, beware of consequences
        OwnShipIndex ownShipIndexStub() {
            return detachedMockFactory.Stub(OwnShipIndex)
        }

        @Bean
        @Primary    //if needed, beware of consequences
        EnemyShipIndex enemyShipIndexStub() {
            return detachedMockFactory.Stub(EnemyShipIndex)
        }
    }
}

The mocks are created in a separate class (outside the Specification) and therefore DetachedMockFactory has to be used (or alternatively SpockMockFactoryBean). Those mocks have to be attached (and detached) to the test instance (the Specification instance), but it is automatically handled by the spock-spring module (as of 1.1). For generic mocks created externally also MockUtil.attachMock() and mockUtil.detachMock() would need to be used to make it work.

As a result it was possible to create and use mocks in the Spring context, but it was not very convenient and it was not commonly used.

Spock 1.2 – first class support

Spring Boot 1.4 brought the new quality to integration testing with (Mockito’s) mocks. It leveraged the idea, originally presented in Springockito back in 2012 (when the Spring configuration was mostly written in XML :) ) to automatically inject mocks (or spies) into the Spring (Boot) context. The Spring Boot team extended the idea and thanks to having it as the internally supported feature it (usually) works reliably just by adding an annotation or two in your test.

Similar annotation-based mechanism is built-in in Spock 1.2.

//@ContextConfiguration just for simplification, @(Test)Configuration is usually more convenient for Spring Boot tests
//Real beans can exist in the context or not
@ContextConfiguration(classes = [ShipDatabase/*, OwnShipIndex, EnemyShipIndex*/])
class ShipDatabaseITSpec extends Specification {

    private static final String ENTERPRISE_D = "USS Enterprise (NCC-1701-D)"
    private static final String BORTAS_ENTERA = "IKS Bortas Entera"

    @SpringBean
    private OwnShipIndex ownShipIndexMock = Stub()  //could be Mock() if needed

    @SpringBean
    private EnemyShipIndex enemyShipIndexMock = Stub()

    @Autowired
    private ShipDatabase shipDatabase

    def "should find ship in both indexes"() {
        given:
            ownShipIndexMock.findByName("Enter") >> [ENTERPRISE_D]
            enemyShipIndexMock.findByName("Enter") >> [BORTAS_ENTERA]
        when:
            List<String> foundShips = shipDatabase.findByName("Enter")
        then:
            foundShips == [ENTERPRISE_D, BORTAS_ENTERA]
    }
}

There is not much to be added. @SpringBean instructs Spock to inject a mock into a Spring context. Similarly, @SpringSpy wraps the real bean with a spy. In a case of @SpringBean it is required to initialize a field to let Spock know if we plan to use a stub or a mock.

In addition, there is also a more general annotation @StubBeans to replace all defined beans with stubs. However, I plan to cover it separately in an another blog post.

Limitations

For those of you who look forward to rewrite all Mockito’s mocks to Spock’s mocks in your Spock tests right after the lecture of this article there is a word of warning. Spock’s mocks – due to their nature and relation to Specification – have some limitations. The implementation under the hood creates a proxy which is injected into the Spring context which (potentially) replaces real beans (stubs/mocks) or wraps them (spies). That proxy is shared between all the tests in the particular test (specification) class. In fact, it also can span across other tests with the same bean/mock declarations in the situation Spring is able to cache the context (similar situation to Mockito’s mocks or Spring integration tests in general).

However, what is really important, a proxy is attached to a tests right before its execution and is detached right after it. Therefore, in fact, every test has it’s own mock instance (it cannot be applied to @Shared fields) and it is problematic for instance to group interactions from different tests and verify them together (which usually is quite sensible, but might lead to some duplication). Nevertheless, with using a setup block (or in-line stubbing) it is possible to share stubbing and interaction expectancy.

Summary

Spock 1.2 finally brings hassle-free Spock’s stubs/mocks/spies support for using them in the Spring context which is comparable with the one provided in Spring Boot for Mockito. It is just enough to add the spock-spring module to the project test dependencies. Despite some limitations, it is one point less for mixing native Spock’s mocking subsystem with external mocking frameworks (such as Mockito) in your Spock (integration) tests. And what is nice, it should work also in plain Spring Framework tests (not only Spring Boot tests). The same feature has been implemented for Guice (but I haven’t tested it).

Furthermore, Spock 1.2 brings also some other changes including better support for Java 9+ and it is worth to give it a try in your test suite (and of course report any potentially spotted regression bugs :) ).

One more good news. In addition to the Leonard’s work who made Spock 1.2 possible and a legion of bug reporters and PR contributors, since recently, there are also some other committers who are working on making Spock even better. Some of them you may know from some other popular FOSS projects. What is more, Spock 1.2 is (preliminary) planned to be the last version based on JUnit 4 and the next stable Spock version could be 2.0, leveraging JUnit 5 and (among others) its native ability to run tests in parallel.

The examples were written using Spock 1.2-RC1. It will be updated to 1.2-final once released. The source code is available from GitHub.

Btw, have you wonder if it is still worth using Spock in the time of JUnit 5? I try to help answer that question in my presentation which will be possible to see at JDD 2018, this October in Kraków, Poland. See you there.

JDD 2018 logo with date

The lead photo based on the Couleur‘s work published in Pixabay, CC0 1.0

Advertisements

Unit tests are very handy. They run fast and it is possible to execute hundreds or even thousands of them very often during development (especially useful when using TDD). Nevertheless from time to time we want to test the correctness of a part of an IoC container configuration and check how those components works together when managed by an IoC context. In this tutorial I will show how to do it in a convenient way.

The easiest solution could be to set up the whole “production” IoC context. Unfortunately depending on the size of a project it can take some time (long minutes) and in addition that configuration is likely to connect to external resources like a database or a message queue which makes restriction where those tests will be able to run. What can we do to fix it?

Very often to test interactions between selected components it is not needed to make the full featured integration tests. We can use two useful techniques together: limiting context scope (?) and mocking. The idea is to set up only needed components. This can be achieved by separate a minimal Spring configuration file using in tests (possible reusing some of existing production files). However very often there is a problem with direct dependencies which behaviors (?) are not needed in our tests, but are required to set up our beans. Doesn’t it look familiar to the situation meet also in unit tests? Mocks (and Mockito) to the rescue.

Our mocks have to be put into Spring context to be able to inject into other beans created by Spring. While it can be done using pure Spring mechanisms, there is a library which makes it much easier – Springockito written by Jakub Janczak.

Note. Pure unit tests are generally much better choice. Tests using IoC context should be only used when we really need to test behaviors within a context.

To start working with Springockito it is required to add its JAR to the project dependencies. Using Maven it could be:

<dependency>
    <groupId>org.kubek2k</groupId>
    <artifactId>springockito</artifactId>
    <version>1.0.4</version>
    <scope>test</scope>
</dependency>

With Gradle:

testCompile "org.kubek2k:springockito:1.0.4"

(change 1.0.4 to the latest released version of Springockito)

Note. The following examples are simplified to does not introduce unneeded distractions. They do not have a context configuration which is worth to test and it would be easier to use pure unit tests (without a Spring context).

Let’s take following configuration where plantWaterer object requires waterSource and waterScheduler beans:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="plantWaterer" class="info.solidsoft.refcard.mockito.PlantWaterer">
        <constructor-arg name="waterSource" ref="waterSource"/>
        <constructor-arg name="waterScheduler" ref="waterScheduler"/>
    </bean>

    <bean id="waterSource" class="info.solidsoft.refcard.mockito.RiverWaterSource">
        <constructor-arg ref="smallRiver"/>
    </bean>

    <bean id="waterScheduler" class="info.solidsoft.refcard.mockito.WaterScheduler"/>

</beans>

RiverWaterSource relies on an external resource which could be problematic during tests. To override it following configuration (with the additional namespace mockito) could be used.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mockito="http://www.mockito.org/spring/mockito"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://www.mockito.org/spring/mockito https://bitbucket.org/kubek2k/springockito/raw/tip/springockito/src/main/resources/spring/mockito.xsd">

    <mockito:mock id="waterSource" class="info.solidsoft.refcard.mockito.WaterSource"/>

</beans>

Make a note that there is even no try to create the original bean. This is very useful in a situation where for example DAO would like to make a connection to a database during start up (which could take some time and is very fragile).

With Springockito it is also very easy to make a spy of existing Spring bean and inject it into another bean instead of the original bean for example to verify made interactions.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mockito="http://www.mockito.org/spring/mockito"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://www.mockito.org/spring/mockito https://bitbucket.org/kubek2k/springockito/raw/tip/springockito/src/main/resources/spring/mockito.xsd">

    <mockito:spy beanName="waterSource"/>

</beans>

Mocks and spies created with a help of Springockito are just like “normal” mocks/spies which can be stubbed and verified. However there are two important differences. The instance of a mock/spy is created by Spring when a context is set up (in opposite to manual call Mockito.mock/spy() or using @Mock/@Spy annotation), so the easiest way to obtain it is to make an injection into our tests class (by name or by type).

@ContextConfiguration({<<configuration-files>>})
public class MockInjectionSpringockitoTest extends AbstractTestNGSpringContextTests {

    @Autowired
    private PlantWaterer plantWaterer;

    @Autowired	//it is safe - Springockito hid the original WaterSource bean
    private WaterSource waterSourceSpy;

    @Test
    public void shouldSpyInjectedObject() {
        //given - mocks/spies are already created, can be stubbed here

        //when
        plantWaterer.waterPlants();

        //then
        verify(waterSourceSpy).startWaterFlow();
    }
}

The seconds important difference is also related to the fact that a mock/spy is created with a context and the same instance is hold until the context shutdown. It can span across many tests or even test classes. It is important to properly reset/initialize mocks/spies manually before every test to avoid an impact of the operations done in previously executed tests. The issue has been already reported and hopefully will be resolved in the further Springockito versions.

Btw, in case of the following error:

org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.mockito.org/spring/mockito]
Offending resource: class path resource [yourSpringConfig.xml]
	at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68)
	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85)
(...)

make sure the Springockito JAR has been successfully added as a project dependency.

In case you prefer annotations over XML Springockito has also something for you. This is a version of Springockito which allow to do similar things, but directly in your test code.

To use it in a project it is required to add an springockito-annatations.jar to your project dependencies.

With Maven:

<dependency>
    <groupId>org.kubek2k</groupId>
    <artifactId>springockito-annotations</artifactId>
    <version>1.0.2</version>
</dependency>

With Gradle:

testCompile "org.kubek2k:springockito-annotations:1.0.2"

(change 1.0.2 to the latest released version of springockito-annotation – the numeration is not synchronized with springockito – it is an independent jar (as of 1.0.2))

@ContextConfiguration(loader = SpringockitoContextLoader.class, locations = {<<the-base-configuration-file>>})
public class MockInjectionSpringockitoTest extends AbstractTestNGSpringContextTests {

    @Autowired
    private PlantWaterer plantWaterer;

    @WrapWithSpy
    @Autowired	//to inject a spy into this field to make a verification
    private WaterSource waterSource; //spy

    @ReplaceWithMock //just replace the original bean with a mock, will be null
                     //it won't be stubbed - no need to inject
    private WateringScheduler wateringScheduler; //mock

    @Test
    public void shouldSpyInjectedObject() {
        //given - mocks/spies are already created, can be stubbed here

        //when
        plantWaterer.waterPlants();

        //then
        verify(waterSource).startWaterFlow();
    }
}

The trick here is to use a custom Spring context loader which checks (by name) if there is any bean which should be replaced with a mock or wrapped with a spy.

The code above causes waterSource bean defined in a configuration file to be wrapped with a spy and wateringScheduler bean to be replaced with a mock (the original wateringScheduler bean will not be created at all). They are both injected into plantWaterer. @ReplaceWithMock and @WrapWithSpy annotations are used only by Springockito to detect which beans should be replaced/wrapped. To get an instance of a mock/spy (to stub it or verify behavior) it is needed to use also an appropriate annotation (@Autowired, @Resource or @Inject) – see waterSource in the previous listing.

There is a limitation which force to use the same field name as a bean which should be replaced/wrapped. It should be fixed in the future.

This post is the second part of the series Beyond the Mockito refcard extending recently released my Mockito reference card.