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

@MockBean is not always used #39

Closed
maxiaohao opened this issue May 23, 2019 · 6 comments
Closed

@MockBean is not always used #39

maxiaohao opened this issue May 23, 2019 · 6 comments
Assignees

Comments

@maxiaohao
Copy link

In a test with @MicronautTest we have a mock bean for a JPA repository:

  @Primary
  @MockBean(FooRepository.class) // or @MockBean(FooRepositoryImpl.class)
  FooRepository mockFooRepository() {
    ...
  }

I inspected that there is a race condition in picking which bean is used in the test, even with @Primary as above. Sometimes the mock bean is used while sometimes the actual RepositoryImpl is used and that is totally random.

@maxiaohao maxiaohao reopened this May 23, 2019
@graemerocher
Copy link
Contributor

Provide an example that reproduces. Really you should not be using Primary in combination with MockBean

@maxiaohao
Copy link
Author

maxiaohao commented May 23, 2019

@graemerocher
Here is an example project that can reproduce the issue: https://github.com/maxiaohao/micronaut-test-issue-reproducer
Please clone and run ./gradlew clean test -i. You will then randomly get 1 of the 4 possible results:

  1. test pass (mock repository is used), and you'll see logs like:
INFO  com.example.ExampleTest - Getting model FooModel(id=1, name=mock model name), mock foo repository is used.
  1. test failing (actual repository is used), and you'll see logs like:
INFO  c.e.repository.FooRepositoryImpl - actual foo repository is used                         
                                                                                                                                                                                                      
com.example.ExampleTest > testFooToBar() FAILED                                                                                                                                                       
    org.opentest4j.AssertionFailedError: expected: <1> but was: <0>                                                                                                                                   
        at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:54)                                                                                                                          
        at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:195)                                                                                                                     
        at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:152)                                                                                                                     
        at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:147)                                                                                                                     
        at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:327)                                                                                                                         
        at com.example.ExampleTest.testFooToBar(ExampleTest.java:47)
  1. test failing (no transaction is in progress). If you uncomment the lines in ExampleSingleton.java that persist barModels, you will also get a higher chance to see following exception:
com.example.ExampleTest > testFooToBar() FAILED
    javax.persistence.TransactionRequiredException: no transaction is in progress
        at org.hibernate.internal.SessionImpl.checkTransactionNeeded(SessionImpl.java:3586)
        at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1447)
        at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1443)
        at org.springframework.orm.hibernate5.SessionFactoryUtils.flush(SessionFactoryUtils.java:147)
        at org.springframework.orm.hibernate5.SpringSessionSynchronization.beforeCommit(SpringSessionSynchronization.java:95)
        at org.springframework.transaction.support.TransactionSynchronizationUtils.triggerBeforeCommit(TransactionSynchronizationUtils.java:96)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.triggerBeforeCommit(AbstractPlatformTransactionManager.java:922)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:730)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:533)
        at io.micronaut.spring.tx.annotation.TransactionInterceptor.intercept(TransactionInterceptor.java:88)
        at io.micronaut.aop.MethodInterceptor.intercept(MethodInterceptor.java:40)
        at io.micronaut.aop.chain.InterceptorChain.proceed(InterceptorChain.java:146)
        at com.example.repository.$BarRepositoryImplDefinition$Intercepted.save(Unknown Source)
        at java.util.stream.ReferencePipeline$11$1.accept(ReferencePipeline.java:372)
        at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
        at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
        at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
        at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
        at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
        at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
        at com.example.singleton.ExampleSingleton.fooToBar(ExampleSingleton.java:32)
        at com.example.ExampleTest.testFooToBar(ExampleTest.java:46)

  1. infinite wait on micronaut application starts - dead lock?

My env:

OS: Arch Linux x86_64
Kernel: 4.19.33-1-lts
openjdk version "1.8.0_212"
OpenJDK Runtime Environment Corretto-8.212.04.1 (build 1.8.0_212-b04)
OpenJDK 64-Bit Server VM Corretto-8.212.04.1 (build 25.212-b04, mixed mode)

Might be related to disabling the auto transaction wrapping for tests with two datasources, from this: #28

On the other side, if @Primary is not used, I get:

io.micronaut.context.exceptions.NonUniqueBeanException: Multiple possible bean candidates found: [com.example.repository.$FooRepositoryImplDefinition$Intercepted, com.example.$ExampleTest$MockFooRepositoryDefinition$Intercepted]

Hope that information helps. Thank you in advance!

@graemerocher graemerocher self-assigned this Jun 3, 2019
@graemerocher
Copy link
Contributor

Thanks for the example, looking into this now.

@graemerocher
Copy link
Contributor

Root cause micronaut-projects/micronaut-core#1740

@graemerocher
Copy link
Contributor

Fixed upstream and will be in 1.1.3 of Micronaut. Thanks for the report.

@maxiaohao
Copy link
Author

@graemerocher 👍 Thanks fox fixing it.

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

2 participants