Search code examples
spring-bootapache-camelspockspring-boot-testspring-camel

Spock with Spring Boot and Camel: Zero interactions with detached mock


I am having some issues with testing my camel context with spring boot.

I am using spring boot 1.5.6, spock 1.1-groovy-2.4, camel 2.19.2, and camel-spring-boot-starter 2.19.2.

I am using a spock mock, and I'm using the DetachedMockFactory in a @TestConfiguration class. All of my beans use constructor injection. I am injecting a mocked @Repository into one of the processor @Components, and I am also injecting it into my test class to define interactions.

I have my test annotated with @SpringBootTest with the classes list including all Processor implementations, and all RouteBuilder extensions. I also have an '@Import' with my TestConfiguration class. I am even using constructor injection for this repository bean in my test!

But it seems that the mock that is injected into the test class is not the one that is in use. Does anyone have an idea what could be wrong? I have tried @DirtiesContext to reload the context both before and after each test, but that did not help.


Solution

  • Problems with DetachedMocks not behaving correctly, e.g., appearing to be the same instance, are usually caused by some framework wrapping them in proxies. For example this can be caused by @Transactional annotation in Spring, which creates a proxy to facilitate jdbc-session management. See also issue #758

    For spring you can use the methods of AopUtils (jdoc). The simple way is to use AopUtils.isAopProxy to check if it is proxied by spring an then unwrap it.

    public static <T> T getTargetObject(Object proxy) throws Exception {
        if (AopUtils.isAopProxy(proxy)) {
            return (T) ((Advised) proxy).getTargetSource().getTarget();
        } else {
            return (T) proxy;
        }
    }
    

    And in a Test

    def "sample service test"() {
        given:
        def sampleRepositryMock = getTargetObject(sampleRepositry)
        when:
        sampleService.doSomething()   // simply invoke sampleRepositry.doSomething() in it
        then:
        1 * sampleRepositryMock.doSomething() 
        0 * _                   
    }
    

    Edit: Since Spock 1.2 there is an extension to automatically unwrap injected beans @UnwrapAopProxy.

    @Inject
    @UnwrapAopProxy
    SampleRepositry sampleRepositryMock