Code Monkey home page Code Monkey logo

micronaut-test's Introduction

Spock: Maven Central JUnit 5: Maven Central Kotest: Maven Central Kotest 5: Maven Central Quality Gate Status

Micronaut Test

This project provides testing extension for JUnit 5, Spock and Kotest to make it easier to test Micronaut applications.

For more information see the Latest or Snapshot Documentation.

Example Spock Test:

import io.micronaut.test.annotation.MicronautTest
import spock.lang.*
import jakarta.inject.Inject

@MicronautTest // Declares the test as a micronaut test
class MathServiceSpec extends Specification {

    @Inject
    MathService mathService // Dependency injection is used to supply the system under test

    @Unroll
    void "should compute #num times 4"() { // This is the test case. #num will be replaced by the values defined in the where: block
        when:
        def result = mathService.compute(num)

        then:
        result == expected

        where:
        num | expected
        2   | 8
        3   | 12
    }
}

Example JUnit 5 Test:

import io.micronaut.test.annotation.MicronautTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

import jakarta.inject.Inject;


@MicronautTest // Declares the test as a micronaut test
class MathServiceTest {

    @Inject
    MathService mathService; // Dependency injection is used to supply the system under test


    @ParameterizedTest
    @CsvSource({"2,8", "3,12"})
    void testComputeNumToSquare(Integer num, Integer square) {
        final Integer result = mathService.compute(num); // Injected bean can be used in test case

        Assertions.assertEquals(
                square,
                result
        );
    }
}

Snapshots and Releases

Snaphots are automatically published to JFrog OSS using Github Actions.

See the documentation in the Micronaut Docs for how to configure your build to use snapshots.

Releases are published to JCenter and Maven Central via Github Actions.

A release is performed with the following steps:

micronaut-test's People

Contributors

altro3 avatar alvarosanchez avatar angelyan avatar avarun42 avatar dependabot-preview[bot] avatar dependabot[bot] avatar dstepanov avatar fitzvinicius avatar goodnic avatar graemerocher avatar ilopmar avatar jameskleeh avatar ledoyen avatar melix avatar micronaut-build avatar msupic avatar nandi avatar osscontributor avatar pgressa avatar puneetbehl avatar rafaelrenanpacheco avatar renovate[bot] avatar sascha-frinken avatar sdelamo avatar sksamuel avatar spikhalskiy avatar timyates avatar tobiasschaefer avatar wetted avatar zacharyklein avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

micronaut-test's Issues

Kotlintest test classes are excluded from test running

If we write a test class with kotlintest without injecting any Micronaut related stuff into the class' constructor, the test class will be totally ignored in test running.

Example repo: https://github.com/adamkobor/micronaut-kotlintest-bug

Example test classes

Working:

@MicronautTest
class IncludedExampleControllerSpec(@Client("/") private val client: RxHttpClient) : BehaviorSpec() {

    init {
        given("an index endpoint") {
            `when`("called") {
                val resp = client.toBlocking().exchange<Any>("/")
                then("the response should be OK") {
                    resp.status.shouldBe(HttpStatus.OK)
                }
            }
        }
    }
}

Ignored:

@MicronautTest
class ExcludedExampleControllerSpec : BehaviorSpec() {

    private val client = startTestApplication().getLowLevelClient()

    init {
        given("the index endpoint") {
            `when`("called") {
                val resp = client.toBlocking().exchange<Any>("/")
                then("the response should be OK") {
                    resp.status.shouldBe(HttpStatus.OK)
                }
            }
        }
    }
}

fun startTestApplication(): EmbeddedServer =
    ApplicationContext
        .build()
        .build()
        .start()
        .getBean(EmbeddedServer::class.java)
        .start()

fun EmbeddedServer.getLowLevelClient(): RxHttpClient =
    this.applicationContext.createBean(RxHttpClient::class.java, this.url)

When we run the test Gradle task, only IncludedExampleControllerSpec will be included in the process.

BeanInstantiationException when using RxClient in Kotlin + Junit + Mockito setup

Example repo https://github.com/pjagielski/micronaut-kotlin-junit-mockbean-problem

My test setup:

@MicronautTest
open class UsersEndpointTest {

    val embeddedServer: EmbeddedServer = ApplicationContext.run(EmbeddedServer::class.java)
    val client: RxHttpClient = RxHttpClient.create(embeddedServer.url)

    @Inject
    lateinit var userReadRepository: UserReadRepository

    @MockBean(SqlUserReadRepository::class)
    fun userReadRepository(): UserReadRepository = mock()
...
}

Gradle test output:

11:27:41.942 [pool-2-thread-1] ERROR i.m.h.s.netty.RoutingInBoundHandler - Unexpected error occurred: Error instantiating bean of type [io.realworld.user.domain.UserReadRepository]: No bean of type [io.realworld.user.endpoint.UsersEndpointTest] exists. Ensure the class is declared a bean and if you are using Java or Kotlin make sure you have enabled annotation processing.
io.micronaut.context.exceptions.BeanInstantiationException: Error instantiating bean of type [io.realworld.user.domain.UserReadRepository]: No bean of type [io.realworld.user.endpoint.UsersEndpointTest] exists. Ensure the class is declared a bean and if you are using Java or Kotlin make sure you have enabled annotation processing.
    at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1335)
    at io.micronaut.context.DefaultBeanContext$1.get(DefaultBeanContext.java:1699)
    at io.micronaut.inject.ParametrizedProvider.get(ParametrizedProvider.java:45)
    at io.micronaut.runtime.context.scope.refresh.RefreshScope.lambda$get$0(RefreshScope.java:91)
    at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
    at io.micronaut.runtime.context.scope.refresh.RefreshScope.get(RefreshScope.java:90)
    at io.micronaut.context.DefaultBeanContext.getScopedBeanForDefinition(DefaultBeanContext.java:1692)
    at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:1625)
    at io.micronaut.context.DefaultBeanContext.getProxyTargetBean(DefaultBeanContext.java:774)
    at io.realworld.user.endpoint.$UsersEndpointTest$UserReadRepositoryDefinition$Intercepted.$resolveTarget(Unknown Source)
    at io.realworld.user.endpoint.$UsersEndpointTest$UserReadRepositoryDefinition$Intercepted.interceptedTarget(Unknown Source)
    at io.realworld.user.endpoint.$UsersEndpointTest$UserReadRepositoryDefinition$Intercepted.findByEmail(Unknown Source)
    at io.realworld.security.domain.UserAuthenticationService.authenticate(UserAuthenticationService.kt:16)

@MockBean is not compatible with @Async : NonUniqueBeanException

  1. Take official testing guide as input: junit5
  2. Add void method to MathService (for example void execute())
  3. Add @Async annotation to method implementation at MathServiceImpl
  4. Get error:
io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for field [mathService] of class: example.rest.MathCollaborationTest

Path Taken: MathCollaborationTest.mathService

	at io.micronaut.context.AbstractBeanDefinition.getBeanForField(AbstractBeanDefinition.java:1354)
	at io.micronaut.context.AbstractBeanDefinition.getBeanForField(AbstractBeanDefinition.java:1148)
	at example.rest.$MathCollaborationTestDefinition.injectBean(Unknown Source)
	at io.micronaut.context.AbstractBeanDefinition.inject(AbstractBeanDefinition.java:360)
	at io.micronaut.context.DefaultBeanContext.doInject(DefaultBeanContext.java:1736)
	at io.micronaut.context.DefaultBeanContext.inject(DefaultBeanContext.java:631)
	at io.micronaut.test.extensions.AbstractMicronautExtension.beforeEach(AbstractMicronautExtension.java:195)
	at io.micronaut.test.extensions.junit5.MicronautJunit5Extension.beforeEach(MicronautJunit5Extension.java:63)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeBeforeEachCallbacks$1(TestMethodTestDescriptor.java:143)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeMethodsOrCallbacksUntilExceptionOccurs(TestMethodTestDescriptor.java:169)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeEachCallbacks(TestMethodTestDescriptor.java:142)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:121)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
	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:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:198)
	at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:136)
	at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.lambda$execute$2(TestTemplateTestDescriptor.java:104)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
	at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
	at java.util.stream.ReferencePipeline$11$1.accept(ReferencePipeline.java:373)
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
	at java.util.stream.ReferencePipeline$11$1.accept(ReferencePipeline.java:373)
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
	at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
	at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
	at java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:270)
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
	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:481)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
	at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
	at java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:270)
	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
	at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
	at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:104)
	at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:40)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
	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:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	at java.util.ArrayList.forEach(ArrayList.java:1257)
	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:139)
	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:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	at java.util.ArrayList.forEach(ArrayList.java:1257)
	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:139)
	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:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	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.DefaultLauncher.execute(DefaultLauncher.java:229)
	at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
	at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: io.micronaut.context.exceptions.NonUniqueBeanException: Multiple possible bean candidates found: [example.service.impl.$MathServiceImplDefinition$Intercepted, example.rest.$MathCollaborationTest$MathServiceDefinition$Intercepted]
	at io.micronaut.context.DefaultBeanContext.findConcreteCandidate(DefaultBeanContext.java:1585)
	at io.micronaut.context.DefaultApplicationContext.findConcreteCandidate(DefaultApplicationContext.java:395)
	at io.micronaut.context.DefaultBeanContext.lastChanceResolve(DefaultBeanContext.java:2154)
	at io.micronaut.context.DefaultBeanContext.findConcreteCandidateNoCache(DefaultBeanContext.java:2084)
	at io.micronaut.context.DefaultBeanContext.lambda$findConcreteCandidate$54(DefaultBeanContext.java:2028)
	at io.micronaut.core.util.clhm.ConcurrentLinkedHashMap.lambda$compute$0(ConcurrentLinkedHashMap.java:721)
	at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1688)
	at io.micronaut.core.util.clhm.ConcurrentLinkedHashMap.compute(ConcurrentLinkedHashMap.java:733)
	at io.micronaut.core.util.clhm.ConcurrentLinkedHashMap.computeIfAbsent(ConcurrentLinkedHashMap.java:710)
	at io.micronaut.context.DefaultBeanContext.findConcreteCandidate(DefaultBeanContext.java:2027)
	at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:1804)
	at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:997)
	at io.micronaut.context.AbstractBeanDefinition.getBeanForField(AbstractBeanDefinition.java:1346)
	... 106 more

Support dynamically injecting properties in the test context

Many integration tests require spinning up dependent services, like a mock server, or an in-memory database. To avoid port conflicts, and hence the test failing randomly, it is highly recommended to start these services on any available port. Obviously, the application needs to be told about these ports, which means the test framework has to provide a way to inject properties dynamically before the tests are run.
Spring allows for this using ApplicationContextInitializer, which can be specified on a test class as follows: @ContextConfiguration(initializers = MyTestContextInitializer.class).

This ticket is for @MicronautTest to support such feature.

@MockBean fails to provide beans from superclasses

Using @MockBean on a test's superclass fails to meet the TestActiveCondition for any subclasses, preventing the bean from being loaded.

Example:

abstract class BaseTest {

    @MockBean
    fun mockMyBean(): MyBean { /* */ }
}

class MyTest : BaseTest() {

    @Inject lateinit var myBean: MyBean

    @Test fun test() { /* */ }
}

Expected Behavior

The mock bean from BaseTest is provided.

Actual Behavior

io.micronaut.context.exceptions.BeanInstantiationException: Error instantiating bean of type  [MyTest]

Message: No bean of type [MyBean] exists. Ensure the class is declared a bean and if you are using Java or Kotlin make sure you have enabled annotation processing.
Path Taken: MyTest.myBean

Without the BaseTest base class, or without using @MockBean at all, the default MyBean is injected. Moving the @MockBean to MyTest provides the mock as expected.

Workaround

Please let me know if there is a better workaround than overriding/moving the @MockBean into each subclass.

The problem appears to just be that the class names are being compared for equality directly rather than checking the type hierarchy.

Environment Information

  • Operating System: Mac OS 10.13.6
  • Micronaut Version: 1.1.1
  • JDK Version: OpenJDK 12.0.1

MicronautTest requires @Inject when Micronaut does not

When micronaut-test was first announced, we tried to refactor some of our tests to use it. We couldn't get it working, so we bailed. Today I spent some more time on this, and realized that there are some inconsistencies between how things work in regular Micronaut beans vs. test classes annotated with @MicronautTest.

Here's one thing that tripped us up.

In my controller, I can directly inject a property from my application.yml as follows:

    $Value('${foo.bar.bat}')
    String myStr

However, I need to add @Inject for this to work within a @MicronautTest:

    @Inject
    $Value('${foo.bar.bat}')
    String myStr

The documentation is very confusing here, because the io.micronaut.test.spock.PropertySpec is used as an example in the guide, and in that example, @Value works without @Inject. But the next example (using property sources) shows @Property with @Inject, which is where I got the idea to try @Value with @Inject as above.

It would be very helpful to either fix this in the code, or make it clear in the docs how (and why) it differs from bean injection in micronaut-core.

Tests are ignored when using JUnit5 & Micronaut Test

Tests are skipped using JUnit5, Micronaut test and Mocking Beans.

Task List

  • Steps to reproduce provided
  • Stacktrace (if present) provided
  • Example that reproduces the problem uploaded to Github
  • Full description of the issue provided (see below)

Steps to Reproduce

  1. create an app via mn-cli
  2. Follow the guide to add JUnit5 support (https://micronaut-projects.github.io/micronaut-test/latest/guide/index.html#junit5)
  3. Add testCompile "org.junit.jupiter:junit-jupiter-engine:5.1.0" otherwise tests don't compile via Gradle
  4. Create a test like:
@MicronautTest
public class ControllerTest {

    @Inject
    Dependency dependency;

    @Test
    public void hello() {
        dependency.doSomething();
        System.out.println("Topzera");
    }

    @MockBean(Dependency.class)
    Dependency another() {
        return Mockito.mock(Dependency.class);
    }
}
  1. Run gradle

Expected Behaviour

Test should pass ( or at least get executed)

Actual Behaviour

Tests are skipped running via Gradle

Environment Information

  • Operating System: Fedora 29
  • Micronaut Version: 1.0.3
  • JDK Version: 11

Example Application

Include test dependencies as part of io.micronaut:micronaut-bom

I'm importing io.micronaut:micronaut-bom:1.0.1 as part of the dependencyManagement block in a Gradle script.

If I specify: testImplementation("io.micronaut.test:micronaut-test-junit5"), it's not getting resolved, I have to specify the same version: 1.0.1. It might be because the dependency notation (read: group, name, etc.) doesn't match with the one in the BOM, but I think it would be nice if it's included. Not sure if you would have to rename something.

Thanks in advance!

Named dependency injection failing

We are using the micronaut-jdbc-hikaricp and both DB2 and postgres, along with MyBatis.

What we are seeing is that if we try to inject a SqlSessionFactory with a named qualifier in a test, it fails with the typical "more than one implementation found" error.

@MicronautTest
class MyTest {
  @Inject
  @Named("db2")
  lateinit var ssf: SqlSessionFactory
}
---
datasources:
  db2:
    url: "jdbc:h2:mem:default;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=DB2;AUTO_RECONNECT=TRUE"
    username: sa
    password: ""
    driverClassName: org.h2.Driver

  pgsql:
    url: "jdbc:h2:mem:default;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=DB2;AUTO_RECONNECT=TRUE"
    username: sa
    password: ""
    driverClassName: org.h2.Driver

---
flyway:
  datasources:
    db2:
      locations: classpath:flyway
      clean-schema: true

And factory:

@Factory
class ConfigurationFactory {
  @Bean
  @Named("db2")
  fun createDb2(appConfig: AppConfig, @Named("db2") env: Environment): Configuration = create(appConfig, env)

  @Bean
  @Named("pgsql")
  fun createPgsql(appConfig: AppConfig, @Named("pgsql") env: Environment): Configuration = create(appConfig, env)
  //snip unimportant stuff
}

What I have done instead is written my test case as below, which works, but obviously not as expected

@MicronautTest
class ApiTest {
  @Inject
  lateinit var spec: RequestSpecification

  @Inject
  lateinit var ctx: ApplicationContext

//  @Inject
//  @Named("db2")
//  lateinit var ssf: SqlSessionFactory

  private fun ssf(): SqlSessionFactory = ctx.getBean(SqlSessionFactory::class.java, Qualifiers.byName("db2"))
}

How to run tests outside transaction?

Hey, I am running tests with @MicronautTest annotation using JPA and Hibernate to test transaction related fragment of implementation and after spending some time to figure out why it is not working I found that Micronaut tests are running inside own transaction:

package example.micronaut;

import static org.junit.jupiter.api.Assertions.assertFalse;

import io.micronaut.test.annotation.MicronautTest;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.junit.jupiter.api.Test;

@MicronautTest
public class TransactionTest {

  @PersistenceContext
  EntityManager entityManager;

  @Test
  public void isInTransactionTest() {
    assertFalse(entityManager.getTransaction().isActive());  // FAILS
  }

}

Is there a handy way to disable that feature or at least change isolation level of that transaction?

Details

Environment

  • System: Arch Linux
  • Micronaut version: 1.1.0.RC1
  • Micronaut Test JUnit version: 1.0.2
  • JDK version: 1.8 (OpenJDK)

Example

The example is available here, to reproduce the issue run gradle test.

MicronautTest with Testcontainers (JUnit5) @BeforeAll

Hi,
in my test setup I am having JUnit5, Micronaut-Test and Testcontainers. I'd like to run an integration test against rabbitmq. I got it done without @MicronautTest but I am having problems integrating @MicronautTest. The problem is, that @MicronautTest triggers its setup even before @BeforeAll or a local static{} .

Especially with @testcontainers it leads to a problem. This is my test class:

import io.micronaut.context.ApplicationContext;
import io.micronaut.context.env.PropertySource;
import io.micronaut.core.util.CollectionUtils;
import io.micronaut.runtime.server.EmbeddedServer;
import io.micronaut.test.annotation.MicronautTest;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.shaded.javax.inject.Inject;

@Testcontainers
@MicronautTest
public class MyTest{

    static final GenericContainer RABBITMQ_CONTAINER;

    static {
        RABBITMQ_CONTAINER = new GenericContainer<>("rabbitmq:3-management")
                .withExposedPorts(5672,15672)
                .withCreateContainerCmdModifier(cmd -> cmd.withHostName("my-rabbit"))
                .withCreateContainerCmdModifier(cmd -> cmd.withName("some-rabbit"));
        RABBITMQ_CONTAINER.start();
    }

    private static EmbeddedServer server;

    @Inject
    ProductClient productClient;

    @BeforeAll
    public static void setupServer() {
        Integer mappedPort = RABBITMQ_CONTAINER.getMappedPort(5672);
        System.out.println(RABBITMQ_CONTAINER.getMappedPort(15672));

        // using the random mapped testcontainers port for rabbitmq
        server = ApplicationContext.run(EmbeddedServer.class, PropertySource.of("test", CollectionUtils.mapOf(
                "rabbitmq.port", mappedPort
        )));

    }

    @AfterAll
    public static void stopServer() throws InterruptedException {
        if (server != null) {
            server.stop();
        }
    }

    @Test
    public void testHello() throws Exception {
        productClient.send("quickstart".getBytes());
        System.out.println();

    }
}

As you can see I tried to ramp up the container manually and via the @TestContainer annotation (just for a test). The rabbitmq test container should start and after it started I need to invoke the getMappedPort() method to get the random port Testcontainers runs my rabbitmq container. This mapped port I need to insert into the MicronautTest configuration. This is not possible as I see it right now because you can only reference a yaml file.
So my goal is it to start MicronautTest with a dynamic configuration (with the dynamically assigned random mapped container port)

This is how I did it without MicronautTest and JUnit 4

public class MyTest {

    @ClassRule
    public static GenericContainer rabbitMq = new GenericContainer<>("rabbitmq:3-management")
            .withExposedPorts(5672,15672)
            .withCreateContainerCmdModifier(cmd -> cmd.withHostName("my-rabbit"))
            .withCreateContainerCmdModifier(cmd -> cmd.withName("some-rabbit"));

    private static EmbeddedServer server;

    private static ProductClient productClient;

    @BeforeClass
    public static void setupServer() {
        Integer mappedPort = rabbitMq.getMappedPort(5672);
        System.out.println(rabbitMq.getMappedPort(15672));

        // using the random mapped testcontainers port for rabbitmq
        server = ApplicationContext.run(EmbeddedServer.class, PropertySource.of("test", CollectionUtils.mapOf(
                "rabbitmq.port", mappedPort
        )));
        productClient=  server.getApplicationContext().getBean(ProductClient.class);

    }

    @AfterClass
    public static void stopServer() throws InterruptedException {
        if (server != null) {
            server.stop();
        }
    }

    @Test
    public void testHello() throws Exception {
        productClient.send("quickstart".getBytes());
        System.out.println();

    }
}

Add support for Junit 5 @Nested classes

When using Junit5's @Nested annotation, any test in a nested class is ignored/skipped.

(Currently running with Micronaut 1.1.4)

@MicronautTest
public class NestedMicronautTest {

	@Inject
	Dependency dependency;

	@Test
	void executedTest() { // passes
		assertTrue(dependency.isTrue());
	}

	@Nested
	class WhenNotAuthenticated {

		@Test
		void ignoredTest() { // never run
			assertTrue(dependency.isTrue());
		}

	}

}

It would be nice to reference the parent classes injected dependencies in nested classes/tests.

Is there a different way to use @MicronautTest to get this to work?

Micronaut and Kotlintest

Hey guys!

I'm one of the commiters at KotlinTest.

I created this issue at KotlinTest, and when I came here to check how I could do it, I saw you guys has the implementation already. It was a great surprise!

If you guys need any help with this, feel free to reach out for us :D

ASM Version Major Compat with Neo4j

I was upgrading our pom/boms to use micronaut 1.0.4 and micronaut-test 1.0.2 and the following was reported by our compat report. Looks like neo4j is asking for asm 6.2 and the rest of the stack is on 5.2.

We are pinning the deps to 6.2 and testing to see if this causes any issues with runtime. Of the below affected libraries the only one we will be using is cassandra, but that is a few weeks out in our dev cycle to even test this.

Would PROBABLY only be an issue where someone wants to use neo4j + any of the other features that might need asm.

[INFO] --- maven-enforcer-plugin:3.0.0-M2:enforce (default-cli) @ micronaut-test-pom ---
[WARNING] Rule 4: org.apache.maven.plugins.enforcer.RequireUpperBoundDeps failed with message:
Failed while enforcing RequireUpperBoundDeps. The error(s) are [
Require upper bound dependencies error for org.ow2.asm:asm:5.2 paths to dependency are:
+-com.optum.cirrus.framework:micronaut-test-pom:1.0.0.PI23-SNAPSHOT
  +-io.micronaut.configuration:micronaut-cassandra:1.0.4
    +-com.datastax.cassandra:cassandra-driver-core:3.1.0
      +-com.github.jnr:jnr-ffi:2.0.7
        +-org.ow2.asm:asm:5.2
and
+-com.optum.cirrus.framework:micronaut-test-pom:1.0.0.PI23-SNAPSHOT
  +-io.micronaut:micronaut-security-jwt:1.0.4
    +-com.nimbusds:nimbus-jose-jwt:6.0.2
      +-net.minidev:json-smart:2.3
        +-net.minidev:accessors-smart:1.2
          +-org.ow2.asm:asm:5.2 (managed) <-- org.ow2.asm:asm:5.0.3
and
+-com.optum.cirrus.framework:micronaut-test-pom:1.0.0.PI23-SNAPSHOT
  +-io.micronaut.configuration:micronaut-cassandra:1.0.4
    +-com.datastax.cassandra:cassandra-driver-core:3.1.0
      +-com.github.jnr:jnr-ffi:2.0.7
        +-org.ow2.asm:asm-tree:5.2
          +-org.ow2.asm:asm:5.2 (managed) <-- org.ow2.asm:asm:5.0.3
and
+-com.optum.cirrus.framework:micronaut-test-pom:1.0.0.PI23-SNAPSHOT
  +-org.neo4j.test:neo4j-harness:3.5.2
    +-org.neo4j:neo4j:3.5.2
      +-org.neo4j:neo4j-cypher:3.5.2
        +-org.neo4j:neo4j-codegen:3.5.2
          +-org.ow2.asm:asm:5.2 (managed) <-- org.ow2.asm:asm:6.2
, 
Require upper bound dependencies error for org.ow2.asm:asm-tree:5.2 paths to dependency are:
+-com.optum.cirrus.framework:micronaut-test-pom:1.0.0.PI23-SNAPSHOT
  +-io.micronaut.configuration:micronaut-cassandra:1.0.4
    +-com.datastax.cassandra:cassandra-driver-core:3.1.0
      +-com.github.jnr:jnr-ffi:2.0.7
        +-org.ow2.asm:asm-tree:5.2
and
+-com.optum.cirrus.framework:micronaut-test-pom:1.0.0.PI23-SNAPSHOT
  +-io.micronaut.configuration:micronaut-cassandra:1.0.4
    +-com.datastax.cassandra:cassandra-driver-core:3.1.0
      +-com.github.jnr:jnr-ffi:2.0.7
        +-org.ow2.asm:asm-commons:5.0.3
          +-org.ow2.asm:asm-tree:5.2 (managed) <-- org.ow2.asm:asm-tree:5.0.3
and
+-com.optum.cirrus.framework:micronaut-test-pom:1.0.0.PI23-SNAPSHOT
  +-io.micronaut.configuration:micronaut-cassandra:1.0.4
    +-com.datastax.cassandra:cassandra-driver-core:3.1.0
      +-com.github.jnr:jnr-ffi:2.0.7
        +-org.ow2.asm:asm-analysis:5.2 (managed) <-- org.ow2.asm:asm-analysis:5.0.3
          +-org.ow2.asm:asm-tree:5.2 (managed) <-- org.ow2.asm:asm-tree:5.0.3
and
+-com.optum.cirrus.framework:micronaut-test-pom:1.0.0.PI23-SNAPSHOT
  +-io.micronaut.configuration:micronaut-cassandra:1.0.4
    +-com.datastax.cassandra:cassandra-driver-core:3.1.0
      +-com.github.jnr:jnr-ffi:2.0.7
        +-org.ow2.asm:asm-util:5.2 (managed) <-- org.ow2.asm:asm-util:5.0.3
          +-org.ow2.asm:asm-tree:5.2 (managed) <-- org.ow2.asm:asm-tree:5.0.3
and
+-com.optum.cirrus.framework:micronaut-test-pom:1.0.0.PI23-SNAPSHOT
  +-org.neo4j.test:neo4j-harness:3.5.2
    +-org.neo4j:neo4j:3.5.2
      +-org.neo4j:neo4j-cypher:3.5.2
        +-org.neo4j:neo4j-codegen:3.5.2
          +-org.ow2.asm:asm-tree:5.2 (managed) <-- org.ow2.asm:asm-tree:6.2
, 
Require upper bound dependencies error for org.ow2.asm:asm-analysis:5.2 paths to dependency are:
+-com.optum.cirrus.framework:micronaut-test-pom:1.0.0.PI23-SNAPSHOT
  +-io.micronaut.configuration:micronaut-cassandra:1.0.4
    +-com.datastax.cassandra:cassandra-driver-core:3.1.0
      +-com.github.jnr:jnr-ffi:2.0.7
        +-org.ow2.asm:asm-analysis:5.2 (managed) <-- org.ow2.asm:asm-analysis:5.0.3
and
+-com.optum.cirrus.framework:micronaut-test-pom:1.0.0.PI23-SNAPSHOT
  +-org.neo4j.test:neo4j-harness:3.5.2
    +-org.neo4j:neo4j:3.5.2
      +-org.neo4j:neo4j-cypher:3.5.2
        +-org.neo4j:neo4j-codegen:3.5.2
          +-org.ow2.asm:asm-analysis:5.2 (managed) <-- org.ow2.asm:asm-analysis:6.2
, 
Require upper bound dependencies error for org.ow2.asm:asm-util:5.2 paths to dependency are:
+-com.optum.cirrus.framework:micronaut-test-pom:1.0.0.PI23-SNAPSHOT
  +-io.micronaut.configuration:micronaut-cassandra:1.0.4
    +-com.datastax.cassandra:cassandra-driver-core:3.1.0
      +-com.github.jnr:jnr-ffi:2.0.7
        +-org.ow2.asm:asm-util:5.2 (managed) <-- org.ow2.asm:asm-util:5.0.3
and
+-com.optum.cirrus.framework:micronaut-test-pom:1.0.0.PI23-SNAPSHOT
  +-org.neo4j.test:neo4j-harness:3.5.2
    +-org.neo4j:neo4j:3.5.2
      +-org.neo4j:neo4j-cypher:3.5.2
        +-org.neo4j:neo4j-codegen:3.5.2
          +-org.ow2.asm:asm-util:5.2 (managed) <-- org.ow2.asm:asm-util:6.2
]

MockBean in Spock test is broken since Micronaut 1.1.3

Since Micronaut 1.1.3 the bean replacement by using @MockBean does not work reliable anymore.

Given the following Spock test you find the following test configuration

@MicronautTest
class ReplaceBeanBugSpec extends Specification {

    @Inject
    @Subject
    AnotherService anotherService

    @Inject
    SuperService superService

    @MockBean(SuperService)
    SuperService superService() {
        Mock(SuperService)
    }
    // test code omitted ... (see below or in link)
}

and two test cases:

void "first test works"() {

        when:
        anotherService.greet("Silvio")

        then:
        1 * superService.hello("Silvio") >> "Good day Silvio"
        0 * _
}
void "second test works"() {

        when:
        anotherService.greet("Angela")

        then:
        1 * superService.hello("Angela") >> "Good day Angela"
        0 * _
}

This test specification demonstrates a bug introduced in Micronaut 1.1.3. When replacing a bean with a Spock test the mock only works in the first test as expected.

Actual behaviour
When running the whole test suite -> test 1 is ok, test 2 fails
When running each test independently -> both are ok (independently)

Expected behaviour
When running the whole test suite -> test 1 & 2 are ok as it was in Micronaut 1.1.2

Please find a sample application in this repository.

@MicronautTest Annotation w Spock Not Inherited from Parent Class

Description

When using @MicronautTest in a spock specification hierarchy, the annotation is not inherited to concrete implementation specifications

Version

Micronaut: 1.1.0.M1
Micronaut Test: 1.0.2

Simple Example

@MicronautTest
class ControllerSpecification extends Specification {
//share test logic and setup
}

class ControllerSpec extends ControllerSpecification {
// test code
}

Workaround

Simply add @MicronautTest to ControllerSpec

Project with multiple test classes annotated with @MicronautTest invokes only one test class

If I define multiple test classes, each annotated with @MicronautTest, then I see only that surefire runs only the test cases of one class, even if multiple test classes are defined. I discovered this in my own project, but it's reproducible with just the hello-world-java example. I'm guessing its something to do with the interplay between MicronautTest extension and JUnit..

How to reproduce:

  1. Check out https://github.com/micronaut-projects/micronaut-examples/tree/master/hello-world-java locally, so using whatever the versions & dependencies are for this example project.

  2. Copy and paste this class:
    https://github.com/micronaut-projects/micronaut-examples/blob/master/hello-world-java/src/test/java/example/HelloControllerTest.java
    ... & call it something like HelloControllerTest2.java

Be sure to leave it inside the same package.

  1. Edit the new file, https://github.com/micronaut-projects/micronaut-examples/blob/master/hello-world-java/src/test/java/example/HelloControllerTest2.java
    ... so that it simply calls Assertions.fail() from within the @test annotated method.

  2. from the command line, in the project root, run:

mvn clean test

Expected Behavior:

  • both test cases are executed
  • HelloControllerTest2.testHello() fails due to Assertions.fail()

Actual Behavior:

  • HelloController2.testHello() is never invoked

Actual Output:
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running example.HelloControllerTest
09:16:17.577 [main] INFO i.m.context.env.DefaultEnvironment - Established active environments: [test]
09:16:19.300 [nioEventLoopGroup-1-4] WARN i.m.validation.ValidatingInterceptor - Beans requiring validation present, but no implementation of javax.validation configuration. Add an implementation (such as hibernate-validator) to prevent this error.
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.116 s - in example.HelloControllerTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]

If I run the tests via my IDE (which happens to be IntelliJ) then I see the expected bahavior.

Refreshable(ACTIVE_MOCKS) breaks Mockito

I'm using micronaut-test with Spek & JUnit5 in Kotlin.
I noticed that when trying to create a @MockBean, it's @Refreshable seems to break some Mockito functions. (Probably because it wraps it as XXDefinition$Intercepted class)

Here's the basic code and the exception - and also a code example (just run ./gradlew test):
mockbean-test.zip

@Factory
class MockFactory {

    // Error:
    @MockBean

    // Simplified: (same error)
    //@Bean
    //@Refreshable(TestActiveCondition.ACTIVE_MOCKS) // copied from @MockBean

    // Works, when only specifying:
    //@Bean

    fun normalTestService() = mock(TestService::class.java)
}

class MockTest : Spek({

    describe("Test API") {
        // ... //
        val testService = context.getBean(TestService::class.java)
        test("normal bean") {
            `when`(testService.test(ArgumentMatchers.anyString()))
                    .thenReturn("Mocked!")
            val result = testService.test("1")
            assert(result == "Mocked!") { "Wrong result: '$result'" }
        }
        // ... //
    }
})

Exception:

io.micronaut.context.exceptions.BeanInstantiationException: Error instantiating bean of type [mockbean.test.TestService]: 
Misplaced or misused argument matcher detected here:

-> at mockbean.test.MockTest$1$1$1.invoke(MockTest.kt:41)

You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
    when(mock.get(anyInt())).thenReturn(null);
    doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
    verify(mock).someMethod(contains("foo"))

This message may appear after an NullPointerException if the last matcher is returning an object 
like any() but the stubbed method signature expect a primitive argument, in this case,
use primitive alternatives.
    when(mock.get(any())); // bad use, will raise NPE
    when(mock.get(anyInt())); // correct usage use

Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.

Embedded server doesn't show errors if it fails to start

JDK: OpenJDK 64-Bit Server VM Zulu11.31+11-CA (build 11.0.3+7-LTS, mixed mode)
Micronaut: 1.2.0.RC1
Micronaut test: 1.1.0.RC1
Kotlin: 1.3.41
JUnit: 5.5.0
IntelliJ: 2019.1.3
Kotlin plugin: 1.3.41

@Inject
private lateinit var server: EmbeddedServer

If the server fails to start, ti doesn't log any warnings or errors.

JUnit 5 - @Value / @Property is not supported when injecting in constructor

Hi,

With 1.1.0 release it is now possible to define constructor for test class to inject application beans.

However it does not work with @Value or @Property.

Code:

@IntegrationTest
class AuthenticationFilterTest(
    private val testData: TestData,
    private val dslContext: DSLContext,
    @Value("\${portal.sessions.duration}")
    private val sessionsDuration: Duration
) {
// ...
}

Error:

org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter [java.time.Duration arg2] in constructor [public app.components.authentication.AuthenticationFilterTest(app.testsupport.TestData,org.jooq.DSLContext,java.time.Duration)].

Meanwhile our workaround is to use field inject for @Value.
Example:

@IntegrationTest
class AuthenticationFilterTest(
    private val testData: TestData,
    private val dslContext: DSLContext
) {

    @Value("\${portal.sessions.duration}")
    private lateinit var sessionsDuration: Duration
    // ...
}

Spock test with @MicronautTest failed - Failed to inject value for parameter [objectMapper]

I try to add the @MicronautTest to my test and I got this error:

io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for parameter [objectMapper] of class: io.micronaut.jackson.convert.ArrayNodeToArrayConverter

Message: Multiple possible bean candidates found: [com.fasterxml.jackson.databind.ObjectMapper, com.fasterxml.jackson.databind.ObjectMapper]
Path Taken: new ArrayNodeToArrayConverter([ObjectMapper objectMapper])

	at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:981)
	at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1282)
	at io.micronaut.context.DefaultBeanContext.addCandidateToList(DefaultBeanContext.java:2171)
	at io.micronaut.context.DefaultBeanContext.getBeansOfTypeInternal(DefaultBeanContext.java:2102)
	at io.micronaut.context.DefaultBeanContext.getBeansOfType(DefaultBeanContext.java:751)
	at io.micronaut.context.DefaultBeanContext.getBeansOfType(DefaultBeanContext.java:521)
	at io.micronaut.context.DefaultBeanContext.getBeanRegistrations(DefaultBeanContext.java:312)
	at io.micronaut.context.DefaultApplicationContext.initializeTypeConverters(DefaultApplicationContext.java:330)
	at io.micronaut.context.DefaultApplicationContext.initializeContext(DefaultApplicationContext.java:184)
	at io.micronaut.context.DefaultBeanContext.readAllBeanDefinitionClasses(DefaultBeanContext.java:1970)
	at io.micronaut.context.DefaultBeanContext.start(DefaultBeanContext.java:155)
	at io.micronaut.context.DefaultApplicationContext.start(DefaultApplicationContext.java:138)
	at io.micronaut.context.ApplicationContextBuilder.start(ApplicationContextBuilder.java:120)
	at io.micronaut.context.ApplicationContext.run(ApplicationContext.java:221)
	at io.micronaut.context.ApplicationContext.run(ApplicationContext.java:202)
	at io.micronaut.context.ApplicationContext.run(ApplicationContext.java:185)
	at example.micronaut.BooksControllerSpec.$spock_initializeSharedFields(BooksControllerSpec.groovy:18)
Caused by: io.micronaut.context.exceptions.NonUniqueBeanException: Multiple possible bean candidates found: [com.fasterxml.jackson.databind.ObjectMapper, com.fasterxml.jackson.databind.ObjectMapper]
	at io.micronaut.context.DefaultBeanContext.findConcreteCandidate(DefaultBeanContext.java:1354)
	at io.micronaut.context.DefaultApplicationContext.findConcreteCandidate(DefaultApplicationContext.java:313)
	at io.micronaut.context.DefaultBeanContext.lastChanceResolve(DefaultBeanContext.java:1829)
	at io.micronaut.context.DefaultBeanContext.findConcreteCandidateNoCache(DefaultBeanContext.java:1770)
	at io.micronaut.context.DefaultBeanContext.lambda$findConcreteCandidate$47(DefaultBeanContext.java:1719)
	at io.micronaut.caffeine.cache.BoundedLocalCache.lambda$doComputeIfAbsent$14(BoundedLocalCache.java:2034)
	at java.util.concurrent.ConcurrentHashMap.compute(ConcurrentHashMap.java:1892)
	at io.micronaut.caffeine.cache.BoundedLocalCache.doComputeIfAbsent(BoundedLocalCache.java:2032)
	at io.micronaut.caffeine.cache.BoundedLocalCache.computeIfAbsent(BoundedLocalCache.java:2015)
	at io.micronaut.caffeine.cache.LocalCache.computeIfAbsent(LocalCache.java:113)
	at io.micronaut.caffeine.cache.LocalManualCache.get(LocalManualCache.java:54)
	at io.micronaut.context.DefaultBeanContext.findConcreteCandidate(DefaultBeanContext.java:1718)
	at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:1529)
	at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:883)
	at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:973)
	... 16 more

My gradle dependencies:

dependencies {
    compile "io.micronaut:runtime-groovy"
    compile "io.micronaut:validation"
    compile "io.micronaut:http-client"
    compile "io.micronaut:http-server-netty"
    compileOnly "io.micronaut:inject-groovy"
    compile group: 'io.micronaut.test', name: 'micronaut-test-spock', version: '1.0.0.RC1'
    runtime "ch.qos.logback:logback-classic:1.2.3"
    testCompile "io.micronaut:inject-groovy"
    testCompile("org.spockframework:spock-core:1.2-groovy-2.4") {
        exclude group: "org.codehaus.groovy", module: "groovy-all"
    }
}

My test:

@MicronautTest
class MyObjectSpec extends Specification {
    void "some test"() {
       //....
    }
}

Add DI support for ArgumentsProvider classes

Writing data-driven tests is challenging with test frameworks, it seems like they all expect static methods which is a pain to deal with.

@MicronautTest
class MyTest {
  @ParameterizedTest
  @ArgumentsSource(DomainValueProvider::class)
  fun `Given domain value should return domain value`(domainValue: DomainValue) {
    given()
      .spec(spec)
      .header(ACCEPT_LANGUAGE, "en")
      .queryParam("key", domainValue.key)
      .queryParam("code", domainValue.code)
      .`when`()
      .get()
      .then()
      .assertThat()
      .statusCode(200)
      .body(matchesJsonSchemaInClasspath("api-schema.json"))
  }
}

First I tried MethodSource but it expects this to be a static method, in which case you cant access instance properties, so that wont work without hacky singleton stuff.

  fun provideDomainValues(): Stream<out Arguments> = ssf().openSession().use {
    it.getMapper(TestDomainValueMapper::class.java).findAll()
  }
    .map { Arguments.of(it) }
    .stream()

Next I tried to implement an ArgumentProvider, but it doesnt seem to participate in DI.

class DomainValueProvider : ArgumentsProvider {
  @Inject
  lateinit var ctx: ApplicationContext

  private fun ssf(): SqlSessionFactory = ctx.getBean(SqlSessionFactory::class.java, Qualifiers.byName("db2"))

  override fun provideArguments(context: ExtensionContext): Stream<out Arguments> = ssf().openSession().use {
    it.getMapper(TestDomainValueMapper::class.java).findAll()
  }
    .map { Arguments.of(it) }
    .stream()
}

Testing POST endpoint

How I can create the test for POST endpoint?

I was look around, but didn't find any examples of testing POST (actually any http methods other than GET). How can I do that?

Micronaut Test with Kotlin

Hi,

I tryed to use MicronautTest for my Kotlin Micronaut services. The tests themself also use kotlin in conjunction with Mockito. My Problem ist that MicronautTest fails to inject my mock with the following error Message:

Failed to inject value for field [collaboratorService] of class:
my.package.MyServiceControllerTest

Path Taken: MyServiceControllerTest.collaboratorService
io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for field [collaboratorService] of class: my.package.MyServiceControllerTest

When I remove the @MockBean annotated method the code compiles again but without the actual mock. This is the test code:


import io.micronaut.test.annotation.MicronautTest
import io.micronaut.test.annotation.MockBean
import org.junit.jupiter.api.Test
import org.mockito.ArgumentMatchers
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.anyString
import org.mockito.Mockito.mock
import javax.inject.Inject

@MicronautTest
open class MyServiceControllerTest {

    @Inject
    lateinit var myServiceControllerClient: MyServiceControllerClient

    @Inject
    lateinit var collaboratorService: CollaboratorService

    @Test
    fun testMyServiceController() {
        Mockito.`when`(
                collaboratorService.compute(
                        ArgumentMatchers.anyString()
                )
        ).thenReturn(5)

	assertEquals(5, myServiceControllerClient.compute("0xb33f"))
    }

    @MockBean(CollaboratorService::class)
    fun collaboratorService(): CollaboratorService {
        return mock(CollaboratorService::class.java)
    }

}

Any ideas?

Best regards,
Johannes

Spock Stub methods returning null within a Lambda

So the issue I am seeing is as follows. I have a Service class that is under test, and as part of that am injecting a number of MockBeans for testing the interactions. So creating the MockBean as follows:

@MockBean(SignupNotificationClient)
    SignupNotificationClient signupNotificationClient() {
        Mock(SignupNotificationClient)
    }

I have defined a stub method which returns an object, as part of my test:

        and: "a publisher for the email send"
        boolean emailSent = false
        Mono<Void> sendEmail = Mono.empty().doOnSubscribe({ emailSent = true}).then()

        then: "should not be found in the database"
        ...
        signupNotificationClient.send(_, _) >>  sendEmail

This is injected into the Service class which I am testing.

 @Inject
    SignupNotificationClient notificationClient;

So the issue I am seeing is that when this method is called within a lambda - the method will return null.

So I have stopped in the debugger to investigate what was happening. So my code looks like this:

return companyExists(cmd.getOrgName(), cmd.getOrgEntity(), cmd.getEmail())
                .flatMap(createOrError(cmd.getFirstName(),
                        cmd.getLastName(),
                        cmd.getEmail(),
                        cmd.getOrgEntity(),
                        cmd.getOrgName()))
                .doOnSuccess((signUp) -> {
                    createWelcomeMessage(cmd.getEmail(), cmd.getOrgName())
                            .subscribeOn(Schedulers.parallel())
                            .subscribe();
                });

So if I stop on the first line here (i.e. at the return) I can use the debugger and call notificationClient.send as many times as I want and get the result back as defined in my test stub.

However, you can see the doOnSuccess method - which uses a lambda, and within it calls the createWelcomeMessage. This method is where the notificationClient.send is actually sent.. (irrelevant stuff stripped out)

private Mono<Void> createWelcomeMessage(String email, String company) {
        ...
        try {
            ...
            return notificationClient.send(UUID.randomUUID().toString(), message);
        }
        catch (NotificationMessageException e) {
            throw Exceptions.propagate(e);
        }
    }

When this method is called here - it returns null. A couple of things I noticed about this is that first of all - it's definitely the same object as I was calling outside of the lambda as is called inside the lambda (as viewing in the debugger). The other thing is that the method on the Mock is definitely available as its returning null rather than throwing no method.

This is one example - but been able to see this with other Injected MockBeans.

Using 1.2.0 BOM (although also tried spock 1.3)

Any thoughts?

Many Thanks

Phil

@MicronautTest EmbeddedServer

Is my understanding correct that, if I have 2 Test classes annotated with @MicronautTest , the ApplicationContext ( and hence the DI, EmbeddedServer, DB Datasource and connection) will all be initialized again ?
If so then is there a way to start ApplicationContext only once across all integration tests in all my integration test classes and reuse it ?
Thank you.

micronaut-test-core pom.xml is missing micronaut-test-spock dependency

The MicronautTest annotation depends on io.micronaut.test.extensions.spock.MicronautSpockExtension. But the generated micronaut-test-core pom.xml doesn't declare a dependency to micronaut-test-spock:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>io.micronaut.test</groupId>
  <artifactId>micronaut-test-core</artifactId>
  <version>1.0.0.RC2</version>
  <dependencies>
    <dependency>
      <groupId>io.micronaut</groupId>
      <artifactId>micronaut-inject</artifactId>
      <version>1.0.0</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>io.micronaut</groupId>
      <artifactId>micronaut-runtime</artifactId>
      <version>1.0.0</version>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
  <name>Micronaut Test</name>
  <description>Testing Framework Extensions for Micronaut</description>
  <url>http://micronaut.io</url>
  <licenses>
    <license>
      <name>The Apache Software License, Version 2.0</name>
      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
      <distribution>repo</distribution>
    </license>
  </licenses>
  <scm>
    <url>scm:[email protected]:micronaut-projects/micronaut-test.git</url>
    <connection>scm:[email protected]:micronaut-projects/micronaut-test.git</connection>
    <developerConnection>scm:[email protected]:micronaut-projects/micronaut-test.git</developerConnection>
  </scm>
  <developers>
    <developer>
      <id>graemerocher</id>
      <name>Graeme Rocher</name>
    </developer>
  </developers>
</project>

As a result, the JDT compiler fails to run the Micronaut Annotation Processor, because m2e doesn't put micronaut-test-spock on the project classpath. Which prevents test annotations to be processed in both Eclipse and vscode-java.

I'm not sure why CLI builds work with javac though.

`@Inject` on test class constructor

I'd like to reuse an idiom from Java Spring+Lombok when using JUnit 5:

@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@SpringBootTest
class SomeTest {
    private final Foo foo;

    // my tests
}

I tried the same with @MicronautTest and @Inject without success. The only option seemed to be field injection, rather than constructor injection. For code hygiene, my team prefers final fields and ctor injection, when possible.

Reading the Micronaut 1.2 RC documentation, this seems supported for beans, so I'm guessing there is something in @MicronautTest which prevents this from working.

Is there a trick I'm missing?

FYI -- We've been exploring Micronaut as a replacement for Spring Boot. Wonderful project!

@Property as meta-annotation

A test class can be annotated with @Property, however when used as a meta-annotation, it is ignored.

The change can be done in AbstractMicronautExtension#beforeClass, but in (at least) two ways:

  • add junit-platform-commons in the compilePath to be able to use AnnotationSupport#findRepeatableAnnotations in test-core
  • copy the JUnit method in an utility class in test-core (with minor adjustements to avoid referencing JUnit classes like Preconditions)
  • ...

@graemerocher what are your thoughts about this ?

Java project with Spock tests has errors in Eclipse

Is there a working example for a Java micronaut project with Spock tests somewhere? I have tried to build such based on a micronaut CLI project and the MathService example from the documentation. After some tries I got the tests to run with Gradle on the command line, but when importing in Eclipse I get an error message in the Groovy test class (which is annotated with @MicronautTest):

Groovy:Groovy compiler error: exception in phase 'semantic analysis' in source unit 'MathServiceSpec.groovy' No such class: org.junit.jupiter.api.extension.ExtendWith

If I remove the @MicronautTest annotation or add the missing junit.jupiter API as a dependency the error disappears but then the test execution in Gradle fails. Test execution in Eclipse doesn't work at all.

My dependencies:

dependencies {
    annotationProcessor "io.micronaut:micronaut-inject-java"
    annotationProcessor "io.micronaut:micronaut-validation"

    compile "io.micronaut:micronaut-inject"
    compile "io.micronaut:micronaut-validation"
    compile "io.micronaut:micronaut-runtime"
    compile "io.micronaut:micronaut-http-client"
    compile "io.micronaut:micronaut-http-server-netty"
    
    testCompile "io.micronaut:micronaut-inject-groovy"
    testCompile "io.micronaut.test:micronaut-test-spock"
    testCompile "org.spockframework:spock-core:1.3-groovy-2.5"
}

JUnit5 test both commits and rolls back transaction

I'm looking in micronaut-test-junit5-1.1.0.RC1-sources.jar!/io/micronaut/test/extensions/junit5/MicronautJunit5Extension.java from the 1.2.0 snapshot, and am confused with this:

    @Override
    public void afterTestExecution(ExtensionContext context) throws Exception {
        commit();
        rollback();
    }

Why does it both commit and rollback? I would have expected it to just rollback.

In my tests, I'm manually rolling back in each test. Is this the wrong approach?


If it should just rollback (as my intuition suggests to me), I'm happy to submit a PR for the change.

NoSuchBeanException whem using @MicronautTest in a Java 11 modular application with JUnit 5

I'm trying to use Micronaut Test in a Java 11 modular application built with Gradle 5.4 with the Gradle module plugin, tested with JUnit 5. And I'm encountering a

io.micronaut.context.exceptions.DependencyInjectionException:
    Failed to inject value for field [foo] of class: foo.FooTest

caused by

io.micronaut.context.exceptions.NoSuchBeanException:
    No bean of type [foo.Foo] exists. Ensure the class is declared a bean
    and if you are using Java or Kotlin make sure you have enabled
    annotation processing.

I have created a simple test case micronaut-test-modules-issue

The root cause seems to be when running tests in Gradle module plugin, the compilation and annotation processing results in the

    build/classes/java/main
    build/classes/java/test

directories have to be put into the same module (because they contain the same packages) through a --patch-module command line argument similar to the following:

--patch-module micronaut.test.modules.issue=build/classes/java/test

while the build/classes/java/main was already put on the module path. And in doing so the copy of the

    META-INF/services/io.micronaut.inject.BeanDefinitionReference

file in the build/classes/java/test directory shadows the one in the build/classes/java/main.

Can't @MockBean an abstract class which declares an interface method it implements as final

Setup

  • Micronaut v1.1.3
  • Micronaut-GRPC v1.0.1
  • Micronaut-Test v1.0.5
  • Kotlin v1.3.11
  • Grpc v1.21.0 (netty-shaded, protobuf, services, stub)

Context

I have a gRPC service which I want to spy on. Every generated service (by protobuf compiler) has a class representing the service and an inner abstract class that implements an interface called BindableService.

Let's suppose I have a proto service called AddressService.

The following code would be generated:

public final class AddressServiceGrpc {

  // bunch of stuff...

  public static abstract class AddressServiceImplBase implements BindableService {
    @Override public final ServerServiceDefinition bindService() { /*do stuff*/ }
  }
}

In my code I have:

open class AddressService : AddressServiceGrpc.AddressServiceImplBase() {
  // do stuff...
  // I want to verify if this method was called
  fun doSomething() {}
}

In my test I have:

@MockBean(AddressService::class)
fun addressService(): AddressServiceGrpc.AddressServiceImplBase {
  return spy { AddressService() }
}

I'm getting the following exception when running the AddressServiceTest (which is properly annotated with @MicronautTest):

io.micronaut.context.exceptions.BeanContextException
Unexpected error loading bean definition [com.xyz.$$AddressServiceTest$AddressServiceDefinition$InterceptedDefinition]: class com.xyz.$AddressServiceTest$AddressServiceDefinition$Intercepted overrides final method bindService.()Lio/grpc/ServerServiceDefinition;

Is there a way to do what I want? Or is it feasible to modify micronaut-test and add this possibility?
Please, let me know if you need more details.

Mixing @MicronautTest with mocks and EmbeddedServer-based tests in a single project

I have @MicronautTest using @MockBean for some bean. And in the same project I have a different test using EmbeddedServer:

EmbeddedServer server = ApplicationContext.build().run(EmbeddedServer.class);
HttpClient client = server.getApplicationContext().createBean(HttpClient.class, server.getURL());

Now, because @MicronautTest is really a @Factory, and @MockBean is really a @Bean, when the EmbeddedServer-based test is run I have following unexpected behavior for the embedded server instance:

  1. All @MicronautTest from the project are visible as beans.
  2. All @MockBean are created and replace the original beans.

I've resolved this by using some specific profile names, however this is highly unexpected and it was hard to debug what happens.

The easy fix is:

  1. Always add some constant environment profile when you start application context for embedded server.
  2. Mark @MicronautTest factories to be always excluded for this profile.

Improve DI lifecycle handling

Not sure what a good issue title is exactly...

  1. This micronaut-test is awesome! Great work!
  2. My team was going down the TestNG route. We were having to implement Registry (as Singleton) pattern to copy dependencies out of appContext, blah blah. It was working, but hacky.
  3. We have since switched our prototype functional tests to micronaut-test, love it! Much cleaner

An observation

@MicronautTest
class MyTest {
  @Inject
  lateinit var foo: Foo

  @BeforeAll
  fun setUp() {
    foo.bar()
  }
}

I am finding that I cannot use @BeforeAll because of probably lifecycle order? The lateinit vars are not yet initialized when the @BeforeAll runs, which kinda defeats the purpose?

Unable to @MockBean(RxHttpClient)

Hi.
I have a bean that uses a low-level RxHttpClient to call out to an external REST api (abridged below)

interface NifiService {
    Flowable<Boolean> isTransformerWorkerRunning()
}
@Singleton
class NifiServiceImpl implements NifiService {

    @Inject
    @Client('transformer-worker')
    RxHttpClient client

    Flowable<Boolean> isTransformerWorkerRunning() {
        client.retrieve(HttpRequest.GET("/nifi-api/flow/status")).map({ true }).onErrorReturnItem(false)
    }

I'm trying to write a unit test that stubs out client so I can test all the code branches without having access to the external api. (which seems a reasonable thing to do)

Here's my attempt - no matter what combination of annotations I use, the real client isn't replaced by the mock.

@MicronautTest
class NifiServiceImplSpec extends Specification {

    @Inject
    NifiServiceImpl nifi

    @Inject
    @Client('transformer-worker')
    RxHttpClient client

    void 'status '() {
        when:
        def status = nifi.isTransformerWorkerRunning()

        then:
        1 * client.retrieve(_) >> Flowable.just('ok')
        status.blockingFirst() == true
    }

    @MockBean(RxHttpClient)
// various attempts at making the mock 'bite'
//    @Named('transformer-worker')
//    @Replaces(named='transformer-worker')
//    @Client('transformer-worker')
    RxHttpClient mockClient() {
        Mock(RxHttpClient)
    }
}

The test output for most annotation combinations is

Too few invocations for:

1 * client.retrieve(_) >> Flowable.just('ok')   (0 invocations)

Unmatched invocations (ordered by similarity):

None

Is this a known limitation, or is it something that could be clarified in the documentation?

@ExtendWith(MockitoExtension.class) conflicting with MicronautTest

Hi Team,

I have a requirement to test my service layer in Micronaut. I am using bean validation in my service layer and so I need validator to be injected in the testing phase and I can't just mock it. However, I want to mock some other classes and so I am also using Mockito as well.

The problem is if I am putting @MicornautTest on my class all the beans marked with @Inject are Not-Null which means that @Inject is working fine. However, as soon as I add @ExtendWith(MockitoExtension.class) to the class and re-run the tests, all the beans marked with @Inject are now null and all the beans marked with @mock are Not-Null.

So it looks like either I can use @Inject in my tests or I can use @mock but not both.

@MicronautTest
@ExtendWith(MockitoExtension.class)
class CashServiceTest {

@Inject
private Validator validator;

@Mock
private AvailableCashClient availableCashClient;

I could have used Mocks everywhere but with Validator that is also not possible as I want to actually test my negative case where the bean validation is failing and the error is propagated through my error handler.

Has anyone faced similar issue earlier? Can you please guide me the correct configuration or check if this is an issue either with Mockito or with Micronaut tests.

Thanks for your assistance.

Mocking of non-interface beans

Hello,

the @MockBean annotation only works if an interface is being the injection point. If you try to mock a bean which is being injected directly, the test will fail to inject anything. If this is by design it would be nice if there was some documentation on this behaviour, especially since generally injection works even if you don't provide interfaces for you beans.

Created beans with @MockBean not injected correctly in other beans

When @MockBean is used the created mock is not (re-)injected correctly in other beans.

I have a controller using a service:

@Controller
public class HelloWorldController {
    private final AcmeService acmeService;

    @Inject
    public HelloWorldController(AcmeService acmeService) {
        this.acmeService = acmeService;
    }

    @Get("/")
    public String handle() {
        acmeServicel.doSomething("test");

        return "Hello World";
    }
}

To simulated different use cases I created the following test:

@MicronautTest
public class HelloWorldControllerTest {

   @Inject
   private AcmeService acmeService;
   @Inject
   @Client("/")
   private RxHttpClient client;

   @MockBean(AcmeService.class)
   public AcmeService acmeService() {
      return Mockito.mock(AcmeService.class);
   }

   @Test
   public void test_without_exception() {

      HttpResponse httpResponse = client.toBlocking().exchange(HttpRequest.GET("/"));
      Assertions.assertEquals(HttpStatus.OK, httpResponse.getStatus());
   }

   @Test
   public void test_with_nullpointer_exception() {

      Mockito.doThrow(new NullPointerException("nullpointer"))
            .when(acmeService)
            .doSomething(Mockito.anyString());

      HttpClientResponseException responseException = Assertions.assertThrows(HttpClientResponseException.class,
            () -> client.toBlocking().exchange(HttpRequest.GET("/")));
   }

}

The second test fails because no exception is thrown.

Debugging the test shows that the method annotated with @MockBean is executed before each test. But only in the first test (test_without_exception) the mocked AcmeService is identical with the AcmeService used by the HelloWorldController.
In the second test (test_with_nullpointer_exception) the mocked AcmeService within the test is now different (because a new mock is created) from the one used by the controller. The AcmeService used by the controller is still the one used during the first test.

According to your doc: "[...] the controller will have a proxy that points to the Mock(..) instance injected. For each iteration of the test the mock is refreshed". This is true but the problem is that the refreshed mock is not used by the controller.

Junit ignores tests when using @MicronautTest in a superclass

I have a superclass annotated with @MicronautTest and two other classes that extends this one. When I try to run the tests within the child classes, all my Junit tests are ignored.

@MicronautTest
public class ApplicationIT {
	@BeforeAll
	public static void loadSomething() {
		//load pre test objects
	}
}

public class SomeTest extends ApplicationIT {
        @Test
	public void someUnitTest() {
              System.out.println("testing");
        }
}

Gradle test result:

com.test.SomeTest  > someUnitTest() STARTED

com.test.SomeTest > someUnitTest() SKIPPED

Any thoughts?

Test fails with two JPA datasources

When testing two jpa datasources with @MicronautTest the first test method always fails with following
error. Unrelated to SUT.

java.lang.IllegalStateException: Transaction synchronization is not active
	at org.springframework.transaction.support.TransactionSynchronizationManager.getSynchronizations(TransactionSynchronizationManager.java:311)
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.triggerAfterCompletion(AbstractPlatformTransactionManager.java:959)
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:865)
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:812)
	at io.micronaut.test.transaction.spring.SpringTestTransactionInterceptor.rollback(SpringTestTransactionInterceptor.java:55)
	at io.micronaut.test.transaction.CompositeTestTransactionInterceptor.rollback(CompositeTestTransactionInterceptor.java:54)
	at io.micronaut.test.extensions.AbstractMicronautExtension.rollback(AbstractMicronautExtension.java:84)
	at io.micronaut.test.extensions.spock.MicronautSpockExtension.lambda$visitSpecAnnotation$2(MicronautSpockExtension.java:92)
	at org.spockframework.runtime.extension.MethodInvocation.proceed(MethodInvocation.java:97)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
	at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:118)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:175)
	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:157)
	at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
	at java.lang.Thread.run(Thread.java:748)

Environment Information

  • Operating System: Linux
  • Micronaut Version: 1.1.0.M2
  • Micronaut Test- Spock Version: 1.0.2
  • JDK Version: 1.8

Example Application

@MockBean is not always used

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.

Create micronaut-test BOM

Similar to how the micronaut bom is created, there should be a micronaut test bom as this grows to more libraries:

Example

<dependency>
    <groupId>io.micronaut.test</groupId>
    <artifactId>micronaut-test-bom</artifactId>
    <version>${micronaut.test.version}</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

Spock's fixture methods don't work when using @MicronautTest

Hi everyone,

I recently tried to use the new @MicronautTest annotation in my tests.
While it has been a breeze with Java/Junit5, using it in a Spock specification seems to prevent the fixture methods from triggering.

Is there any limitation that has not been documented ? Or is it a bug ?

Spock's cleanupSpec fixture method doesn't work when using @MicronautTest

cleanupSpec is not called when @MicronautTest annotation is present. Problem is similar to #3.

@MicronautTest(application = Application.class)
class Test extends Specification {


    def setupSpec() {
        println("setupSpec")
    }

    def cleanupSpec() {
        println("cleanupSpec")
    }

    def "test"() {
        expect:
        true
    }

}

^ "cleanupSpec" is not printed

I'm using micronaut-bom 1.2.0, micronaut-test-spock 1.1.0, spock-core 1.2-groovy-2.4

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.