1

In unit test I try to spy on following intceptor class, on method org.acme.LoggingInterceptor#log(java.lang.String)

package org.acme;

import javax.enterprise.context.ApplicationScoped;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;

import io.quarkus.arc.Priority;
import io.quarkus.logging.Log;

@Logging
@Priority(10)
@Interceptor
@ApplicationScoped
public class LoggingInterceptor {

    @AroundInvoke
    Object log(InvocationContext ctx) throws Exception {
        log("inside LoggingInterceptor @AroundInvoke");
        return ctx.proceed();
    }

    public void log(String message) {
        Log.info(message);
    }
}

I tried with quarkus test by @InjectSpy and also by creating spy directly in the test by Mockito.spy(..) Both fails

1st: fails already when creating the test, error: Invalid use of io.quarkus.test.junit.mockito.InjectSpy - could not resolve the bean of type: org.acme.LoggingInterceptor. Offending field is loggingInterceptor of test class class org.acme.LoggingInterceptorTest1_Subclass

@QuarkusTest
public class LoggingInterceptorTest1 {

//FIXME fails with: Invalid use of io.quarkus.test.junit.mockito.InjectSpy - could not resolve the bean of type: org.acme.LoggingInterceptor. Offending field is loggingInterceptor of test class class org.acme.LoggingInterceptorTest1_Subclass 
    @InjectSpy
    LoggingInterceptor loggingInterceptor;

    @Test
    public void test() ...

2nd: fails with: Wanted but not invoked: loggingInterceptor.log();

@QuarkusTest
public class LoggingInterceptorTest2 {

    @Test
    public void testAroundInvoke() {
        LoggingInterceptor loggingInterceptor = Mockito.spy(LoggingInterceptor.class);

        serviceMethodWithInterceptor();

        ArgumentCaptor<String> logMessageCaptor = ArgumentCaptor.forClass(String.class);
        Mockito.verify(loggingInterceptor).log(logMessageCaptor.capture());

        //FIXME fails with: Wanted but not invoked: loggingInterceptor.log(<Capturing argument>);
        assertEquals("inside LoggingInterceptor @AroundInvoke", logMessageCaptor.getValue());
    }

Sample project here: https://github.com/syr/quarkus-resteasy-postgres/tree/spy_on_interceptor

syr
  • 836
  • 1
  • 12
  • 28

1 Answers1

0

The first thing that's wrong here is that the interceptor is annotated @ApplicationScoped. Quoting the CDI specification:

Instances of interceptors are dependent objects of the bean instance they intercept.

Newer versions of Quarkus will actually fail the deployment when such incorrect interceptor exists, to satisfy this rule:

If an interceptor declares any scope other than @Dependent, the container automatically detects the problem and treats it as a definition error.

Second, the @InjectMock and @InjectSpy mechanism only works for normal scoped beans, as described in https://quarkus.io/guides/getting-started-testing#quarkus_mock (this is because for normal scoped beans, what gets injected is not an "actual" instance, but a client proxy, which is responsible for looking up the instance -- and that is also how mocking is done).

Since interceptors are never normal scoped, @InjectMock and @InjectSpy can't work for them.

Ladicek
  • 5,970
  • 17
  • 20
  • Ok, thanks for clarifying. So this means there is no way to spy on interceptors, right? – syr Jun 13 '23 at 16:42