Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot use @InjectMock with mybatis Mapper interfaces #217

Open
Leibnizhu opened this issue Aug 24, 2022 · 5 comments
Open

Cannot use @InjectMock with mybatis Mapper interfaces #217

Leibnizhu opened this issue Aug 24, 2022 · 5 comments

Comments

@Leibnizhu
Copy link

Leibnizhu commented Aug 24, 2022

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.

@spearheadOne
Copy link

facing the same issue

@spearheadOne
Copy link

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

@zhfeng
Copy link
Collaborator

zhfeng commented Apr 18, 2023

@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!

@spearheadOne
Copy link

@renemarkvard-sosint
Copy link

I'm facing the same issue. Unfortunately the Mockito.mock() and MockitoAnnotations.openMocks(this) does not work!

The mocks are created in the test class, but they are not injected into the test-subject (the object @Inject'ed into the test-class).
.. at least that is what I'm seeing - but is also alligns with why your test in the example is failing.
When I reproduce the linked example my mappers in my service are actual MyBatis mapperProxy instanses and NOT the expected Mockito mocks.

The issue we are facing is described in this bug: quarkusio/quarkus#40152
.. and it does not seem that the Quarkus Devs think that fixing this is worth the effort.

One fix is changing the MapperProxies to be @ApplicationScoped and not @singleton.
.. I have no clue if this is even possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants