quarkus-mybatis icon indicating copy to clipboard operation
quarkus-mybatis copied to clipboard

Cannot use @InjectMock with mybatis Mapper interfaces

Open Leibnizhu opened this issue 3 years ago • 4 comments

I'm trying to mock a mybatis Mapper interface for unit test.

The mapper interface is like :

@Mapper
public interface XxxMapper  {
   @Select("SELECT count(*) FROM xxx")
    long count();
}

unit test:

@QuarkusTest
public class XxxServiceTest {
    @InjectMock
    XxxMapper xxxMapper;

    @Test
    void countTest() {
        Mockito.when(xxxMapper.count()).thenReturn(100L);
        System.out.println(xxxMapper.count());
    }
}

Running this test will fail with :

org.junit.jupiter.api.extension.TestInstantiationException: Failed to create test instance
	at io.quarkus.test.junit.QuarkusTestExtension.initTestState(QuarkusTestExtension.java:793)
	at io.quarkus.test.junit.QuarkusTestExtension.interceptTestClassConstructor(QuarkusTestExtension.java:752)
	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)
        ..............
Caused by: java.lang.IllegalStateException: Invalid use of io.quarkus.test.junit.mockito.InjectMock - the injected bean does not declare a CDI normal scope but: javax.inject.Singleton. Offending field is xxxMapper of test class class com.github.leibnizhu.XxxServiceTest
	at io.quarkus.test.junit.mockito.internal.CreateMockitoMocksCallback.getBeanInstance(CreateMockitoMocksCallback.java:115)
	at io.quarkus.test.junit.mockito.internal.CreateMockitoMocksCallback.afterConstruct(CreateMockitoMocksCallback.java:36)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at io.quarkus.test.junit.QuarkusTestExtension.initTestState(QuarkusTestExtension.java:782)
	... 65 more

As https://quarkus.io/guides/getting-started-testing#further-simplification-with-injectmock said:

By default, the @InjectMock annotation can be used for any normal CDI scoped bean (e.g. @ApplicationScoped, @RequestScoped). Mocking @Singleton beans can be performed by setting the convertScopes property to true (such as @InjectMock(convertScopes = true). This will convert the @Singleton bean to an @ApplicationScoped bean for the test.

I tried convertScopes = true :

    @InjectMock(convertScopes = true)
    XxxMapper xxxMapper;

but the test still failed with the same error.

Leibnizhu avatar Aug 24 '22 10:08 Leibnizhu

facing the same issue

spearheadOne avatar Apr 09 '23 20:04 spearheadOne

Workaround is to mock mapper using Mockito.mock(), but some of my tests fail because mock returns null value

spearheadOne avatar Apr 15 '23 10:04 spearheadOne

@abondar24 Nice catch! and is it possible to share your test? And I think it could be very helpful for other people. Also the contribution is welcome!

zhfeng avatar Apr 18 '23 08:04 zhfeng

@zhfeng here is a test: https://github.com/abondar24/QuarkusDemo/blob/master/src/test/java/org/abondar/experimental/quarkusdemo/service/PersonServiceTest.java Some failing tests are disabled now.

spearheadOne avatar Apr 18 '23 21:04 spearheadOne