quarkus-mybatis
quarkus-mybatis copied to clipboard
Cannot use @InjectMock with mybatis Mapper interfaces
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.
facing the same issue
Workaround is to mock mapper using Mockito.mock(), but some of my tests fail because mock returns null value
@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 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.