transgressoft
transgressoft

Reputation: 165

How to use a separate profile/environment data source for Micronaut test in Kotlin?

I'm trying to use two data sources for my Micronaut web application written in Kotlin: the one with a mysql database, and one in memory H2 database to be used when executing the tests.

I've tried using only the h2 database as the default production data source, so the configuration fields regarding it should be correct.

The application runs as expected with the mysql data source by executing ./gradlew run

  1. I've tried placing the data sources in separate configuration files, application.yml and application-test.yml in src/main/resources/ directory and also placing only application-test.yml in src/test/resources/, without result.
  2. Adding @MicronautTest annotation declaring there the test environment and application = BookieSparaerverApplication params didn't work.
  3. Adding @TypeHint(Genre::class, Book::class, DefaultGenreRepository::class) annotation to BookieServerApplication didn't work.

These are the relevant fields of the src/main/resources/application.yml configuration file

datasources:
  default:
    url: 'jdbc:mysql://localhost:3306/bookie-server?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=false'
    dbCreate: create-update
    driverClassName: com.mysql.cj.jdbc.Driver
    dialect: org.hibernate.dialect.MySQL5InnoDBDialect
    username: root
    password: root

jpa:
  default:
    entity-scan:
      packages:
        - 'com.transgressoft.bookieserver.domain'
    properties:
      hibernate:
        hbm2ddl:
          auto: update
        show_sql: true

And this is the src/test/resources/application-test.yml file:

datasources:
  default:
    url: ${JDBC_URL:`jdbc:h2:mem:default;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE`}
    username: ${JDBC_USER:sa}
    password: ${JDBC_PASSWORD:""}
    driverClassName: ${JDBC_DRIVER:org.h2.Driver}

jpa:
  default:
    entity-scan:
      packages:
        - 'com.transgressoft.bookieserver.domain'
    properties:
      hibernate:
        hbm2ddl:
          auto: update
        show_sql: true

When I execute the test (GenreControllerSpec in the code), looks like the EntityManager bean is not created and therefore the DAO class cannot be instantiated (in my code is the GenreRepository class).

This is the full log message:

Internal Server Error: Failed to inject value for parameter [entityManager] of class: com.transgressoft.bookieserver.domain.$DefaultGenreRepositoryDefinition$Intercepted

Message: No bean of type [javax.persistence.EntityManager] exists. Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).
Path Taken: new $GenreControllerDefinition$Intercepted([GenreRepository genreRepository],BeanContext beanContext,Interceptor[] interceptors) --> new $DefaultGenreRepositoryDefinition$Intercepted([EntityManager entityManager],ConfigurationProperties applicationConfiguration,BeanContext beanContext,Interceptor[] interceptors)
io.micronaut.http.client.exceptions.HttpClientResponseException: Internal Server Error: Failed to inject value for parameter [entityManager] of class: com.transgressoft.bookieserver.domain.$DefaultGenreRepositoryDefinition$Intercepted

The full project code is accesible here https://github.com/octaviospain/bookie-server/tree/feature/jpa-and-hibernate and to reproduce above logs just execute ./gradlew test and open the report, or run it with logs activated.

EDIT: I've updated the description with Ivan Lopez's suggestion, but error and expected result remains the same.

Upvotes: 4

Views: 5471

Answers (2)

James Kleeh
James Kleeh

Reputation: 12228

Your example application is using 1.1.1 of micronaut-hibernate-jpa which does not support

jpa:
  default:
    entity-scan:
      packages:
        - 'com.transgressoft.bookieserver.domain'

You must use jpa.default.packages-to-scan instead as the documentation states.

Upvotes: 1

Iván López
Iván López

Reputation: 944

I think you have missunderstood how defining datasources work. When setting:

datasources:
  production:
    ...

  test:
    ...

jpa:
  production:
    ...

  test:
    ...

You are telling Micronaut: "I want you to create two datasources, one named production and other named test at the same time. Both datasources will be available to the application and you can inject them using the names defined (production and test) and qualifiers.

What you need to do is define in src/main/resources/application.yml only one datasource. Micronaut use default name as the default one:

datasources:
  default:
    ... // your production MySQL database 

jpa:
  default:
    ... // configuration for MySQL database

And then you can override anything defined in application.yml just creating src/test/resources/application-test.yml with the content:

datasources:
  default:
    ... // your test H2 database 

jpa:
  default:
    ... // configuration for H2 database

Hope it makes sense. You can find more information about it here: https://docs.micronaut.io/latest/guide/index.html#config

Upvotes: 4

Related Questions