1

Quarkus offers a internal logger producer (since 1.11.x), so there is no custom logger producer. For a unit test, I need to mock these logger because of the verify-method fo Mockito.

import org.jboss.logging.Logger;

@QuarkusTest
public class ApplicationExceptionMapperTest {

  @InjectMock
  Logger logger;

  @Test
  void simpleTest() {
    // mapper throws exception
    Response response = mapper.toResponse(new IllegalArgumentException());

    Assertions.assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus());

    Mockito.verify(logger, Mockito.times(1)).error(Mockito.anyString(), Mockito.any(IllegalArgumentException.class));
  }
}

The problem is, when executing the test, I get a NPE:

org.junit.jupiter.api.extension.TestInstantiationException: Failed to create test instance

    at io.quarkus.test.junit.QuarkusTestExtension.initTestState(QuarkusTestExtension.java:725)
    at io.quarkus.test.junit.QuarkusTestExtension.interceptTestClassConstructor(QuarkusTestExtension.java:689)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.api.extension.InvocationInterceptor.interceptTestClassConstructor(InvocationInterceptor.java:72)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:77)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestClassConstructor(ClassBasedTestDescriptor.java:342)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateTestClass(ClassBasedTestDescriptor.java:289)
    at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.instantiateTestClass(ClassTestDescriptor.java:79)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:267)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$2(ClassBasedTestDescriptor.java:259)
    at java.base/java.util.Optional.orElseGet(Optional.java:369)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$3(ClassBasedTestDescriptor.java:258)
    at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:31)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:101)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:100)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:65)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$1(NodeTestTask.java:111)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:111)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:79)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)
    at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:221)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at io.quarkus.test.junit.QuarkusTestExtension.initTestState(QuarkusTestExtension.java:717)
    ... 61 more
Caused by: java.lang.NullPointerException
    at io.quarkus.arc.runtime.LoggerProducer.getSimpleLogger(LoggerProducer.java:25)
    at io.quarkus.arc.runtime.LoggerProducer_ProducerMethod_getSimpleLogger_5859fcbc233b38eb09604548b809f68a02e7d55b_Bean.create(LoggerProducer_ProducerMethod_getSimpleLogger_5859fcbc233b38eb09604548b809f68a02e7d55b_Bean.zig:193)
    at io.quarkus.arc.runtime.LoggerProducer_ProducerMethod_getSimpleLogger_5859fcbc233b38eb09604548b809f68a02e7d55b_Bean.get(LoggerProducer_ProducerMethod_getSimpleLogger_5859fcbc233b38eb09604548b809f68a02e7d55b_Bean.zig:223)
    at io.quarkus.arc.runtime.LoggerProducer_ProducerMethod_getSimpleLogger_5859fcbc233b38eb09604548b809f68a02e7d55b_Bean.get(LoggerProducer_ProducerMethod_getSimpleLogger_5859fcbc233b38eb09604548b809f68a02e7d55b_Bean.zig:258)

Is this a Quarkus-bug or do I need anything else to get this test work as expected?

Mani76
  • 357
  • 1
  • 3
  • 14
  • 1
    Looking at `LoggerProducer`, the logger is produced with scope `@Dependent`. `@InjectMock` requires the scope of the bean to be a normal scope, so this is unfortunately not going to work. (The error message doesn't exactly pinpoint the problem, but I'm pretty sure it's closely related. The `LoggerProducer` injects an `InjectionPoint`, which is only possible for `@Dependent` beans, and `@Dependent` beans are not supported by the `@InjectMock` mechanism.) – Ladicek May 21 '21 at 10:52
  • 1
    Is there any other way to verify (any) logger interaction with Quarkus? Most of the time i need to annotate my classes with ``` @ExtendWith(MockitoExtension.class) ``` instead of ``` @QuarkusTest ``` to have full mock-support. More and more I think I should stop this project with Quarkus and use Spring instead. – Mani76 May 28 '21 at 13:52
  • I'm in the same boat. This sucks big time! – DannyThunder Jun 10 '21 at 14:37

2 Answers2

2

I have a workaround for this issue. Not sure if its proper or not and didn't see your class too.

So instead of this

  @Test
  void simpleTest() {
    // mapper throws exception
    Response response = mapper.toResponse(new IllegalArgumentException());

    Assertions.assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus());

    Mockito.verify(logger, Mockito.times(1)).error(Mockito.anyString(), Mockito.any(IllegalArgumentException.class));
  }

Try this


  @Inject
  MockLoggerProducer mockLoggerProducer;

  @Test
  void simpleTest() {
    // mapper throws exception
    Response response = mapper.toResponse(new IllegalArgumentException());

    Assertions.assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus());

    Logger logger = mockLoggerProducer.getMockLogger(Mapper.class);
    Mockito.verify(logger, Mockito.times(1)).error(Mockito.anyString(), Mockito.any(IllegalArgumentException.class));
  }

    @Alternative
    @Priority(1)
    @Singleton
    static class MockLoggerProducer {
        Map<Class<?>, Logger> loggers = new HashMap<>();

        @Produces
        Logger getSimpleLogger(InjectionPoint injectionPoint) {
            Logger logger = loggers.get(injectionPoint.getMember().getDeclaringClass());
            if (logger == null) {
                logger = mock(Logger.class);
                loggers.put(injectionPoint.getMember().getDeclaringClass(), logger);
            }
            return logger;
        }

        Logger getMockLogger(Class<?> clazz) {
            return loggers.get(clazz);
        }
    }

Using quarkus 2.0.2 this works for me

Umut Shn
  • 211
  • 2
  • 7
0

I avoid totally @QuarkusTest and other quarkus related annotations, and using only Mockito annotations, it works.

import org.jboss.logging.Logger;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class MyBeanTest {
    @InjectMocks
    private MyBean bean = new MyBean();

    @Mock
    Logger logger;
    // because it does nothing when logging, so you don't need to stub like `doNothing()...`.

    @Test
    ...(all is fine)

}
WesternGun
  • 11,303
  • 6
  • 88
  • 157