如何在Kotlin中使用单独的配置文件/环境变量来进行Micronaut测试?

3
我想在用Kotlin编写的Micronaut Web应用程序中使用两个数据源,一个是MySQL数据库,另一个是内存中的H2数据库,用于执行测试。

我尝试只使用h2数据库作为默认的生产数据源,因此与其相关的配置字段应该是正确的。

通过执行./gradlew run,mysql数据源下应用程序可以正常运行。

  1. 我尝试将数据源放置在不同的配置文件中,application.ymlapplication-test.yml分别放在src/main/resources/目录中,也仅将application-test.yml放置在src/test/resources/中,但都没有结果。
  2. 添加@MicronautTest注释,在那里声明test环境和application = BookieSparaerverApplication参数无效。
  3. BookieServerApplication添加@TypeHint(Genre::class, Book::class, DefaultGenreRepository::class)注释无效。

这些是src/main/resources/application.yml配置文件的相关字段。

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

这是 src/test/resources/application-test.yml 文件:

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

当我执行测试(代码中的GenreControllerSpec),看起来EntityManager bean没有被创建,因此DAO类无法实例化(在我的代码中是GenreRepository类)。
这是完整的日志信息:
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

完整的项目代码在此处可访问:https://github.com/octaviospain/bookie-server/tree/feature/jpa-and-hibernate,若要重现上述日志,请执行 ./gradlew test 并打开报告,或者开启日志运行测试。
注:根据Ivan Lopez的建议,我已更新了描述,但错误和预期结果仍然相同。
2个回答

4
我认为你误解了数据源的定义方式。在设置时:
datasources:
  production:
    ...

  test:
    ...

jpa:
  production:
    ...

  test:
    ...

你想告诉Micronaut: "我希望你同时创建两个数据源,一个名为production,另一个名为test。这两个数据源都将对应用程序可用,并且可以使用所定义的名称(productiontest)和限定符进行注入。"
你需要做的是在src/main/resources/application.yml中只定义一个数据源。Micronaut会使用default作为默认名称。
datasources:
  default:
    ... // your production MySQL database 

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

接下来,您可以通过创建 src/test/resources/application-test.yml 文件来覆盖任何在 application.yml 中定义的内容:

只需将所需内容写入文件即可。

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

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

希望这有意义。您可以在此处找到更多有关它的信息:https://docs.micronaut.io/latest/guide/index.html#config

感谢您的澄清,但结果和日志仍然相同,这并没有解决我想要实现的目标。事实上,我已经按照您在配置中的建议编辑了问题,以便其他用户也可以专注于解决它。请花一分钟时间查看提供的代码(现已更新),并检查其是否与描述的结果相同。 - transgressoft
@Sap 如果您使用Micronaut Data JDBC,则需要在注释和配置中定义方言。请参见https://micronaut-projects.github.io/micronaut-data/latest/guide/index.html#_setting_the_dialect 原因是查询在编译时预先计算,因此它们需要为正确的数据库准备并且不能是“通用”的。 - Iván López
那么转移到JPA应该解决这个问题吗?如果是的话,我将花时间修复迁移到JPA+Hiberante后遇到的javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not prepare statement错误。 - Sap
@Sap 我也遇到了同样的问题,我的应用程序将使用mysql,而在集成测试中,我想使用h2。但是由于在存储库上必须使用@JdbcRepository(dialect = Dialect.H2),那么我不能使用micronaut-data-jdbc吗? - AmitB10
1
@amitb10 我最终使用了测试容器,并将一个 application.yml 文件放在 test/resources 文件夹中。 - Sap
显示剩余2条评论

1
您的示例应用程序正在使用1.1.1版本的micronaut-hibernate-jpa,该版本不支持。
jpa:
  default:
    entity-scan:
      packages:
        - 'com.transgressoft.bookieserver.domain'

正如文档所述,您必须使用jpa.default.packages-to-scan


谢谢,这使得EntityManager能够在测试中被创建和使用,但是还缺少一件事情,就是让测试使用测试配置文件和h2数据源ApplicationContext.run(EmbeddedServer::class.java, "test") - transgressoft

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接