4.9.1. 中间件集成测试

中间件继承测试运行在具有完整功能的 Spring 容器里,而且可以连接数据库。在这些测试类里面,可以运行中间件里面各细分层的代码,比如从 ORM 层到 Service 层。

Studio 创建新项目之后,可以在 core 模块的包内找到两个类:一个测试容器类和一个测试示例类。测试容器类会启动中间件的 Spring 容器,该容器用来做测试。测试示例类使用这个容器并演示如何用实体测试一些操作。

我们看看生成的测试容器类,怎么能满足我们的需求。

该类必须继承 CUBA 提供的 TestContainer 类。在构造器中,需要做下面这些事:

  • 需要在 appComponents 列表中添加项目中使用的 应用程序组件(扩展插件)。

  • 如果需要,在 appPropertiesFiles 列表指定附加的应用程序属性文件。

  • 调用 autoConfigureDataSource() 方法使用来自应用程序属性或者 context.xml 的信息初始化测试数据源。

生成的测试容器会提供与应用程序相同的数据库连接,所以即使修改了类型或者 JDBC 数据源的定义,测试用例还是会使用主数据存储运行。

使用同一个数据库进行测试和运行应用程序有一个弊端:手动输入的数据会干扰测试数据并有可能破坏测试用例的执行。避免的方法就是为测试单独配置一个数据库。我们建议使用和主数据存储同类型的数据库作为测试数据库,以便使用同一组 数据库迁移脚本。下面是在本地 PostgreSQL 配置测试数据库的一个示例。

首先,在 build.gradle 添加测试数据库创建的 任务

  1. configure(coreModule) {
  2. // ...
  3. task createTestDb(dependsOn: assembleDbScripts, type: CubaDbCreation) {
  4. dbms = 'postgres'
  5. host = 'localhost'
  6. dbName = 'demo_test'
  7. dbUser = 'cuba'
  8. dbPassword = 'cuba'
  9. }

然后在测试源码的根包(比如 modules/core/test/com/company/demo/test-app.properties)内创建 test-app.properties 文件,并制定测试数据库的连接属性:

  1. cuba.dataSource.host = localhost
  2. cuba.dataSource.dbName = demo_test
  3. cuba.dataSource.username = cuba
  4. cuba.dataSource.password = cuba

添加该文件至测试容器的 appPropertiesFiles 列表:

  1. public class DemoTestContainer extends TestContainer {
  2. public DemoTestContainer() {
  3. super();
  4. appComponents = Arrays.asList(
  5. "com.haulmont.cuba"
  6. );
  7. appPropertiesFiles = Arrays.asList(
  8. "com/company/demo/app.properties",
  9. "com/haulmont/cuba/testsupport/test-app.properties",
  10. "com/company/demo/test-app.properties" // your test properties
  11. );
  12. autoConfigureDataSource();
  13. }

运行测试用例之前,执行这个任务创建测试数据库:

  1. ./gradlew createTestDb

这个测试容器应当在测试类里面作为 @RegisterExtension 注解指定的 JUnit 5 扩展:

  1. package com.company.demo.core;
  2. import com.company.demo.DemoTestContainer;
  3. import com.company.demo.entity.Customer;
  4. import com.haulmont.cuba.core.entity.contracts.Id;
  5. import com.haulmont.cuba.core.global.AppBeans;
  6. import com.haulmont.cuba.core.global.DataManager;
  7. import org.junit.jupiter.api.BeforeAll;
  8. import org.junit.jupiter.api.Test;
  9. import org.junit.jupiter.api.extension.RegisterExtension;
  10. import static org.junit.jupiter.api.Assertions.assertEquals;
  11. public class CustomerTest {
  12. // Using the common singleton instance of the test container which is initialized once for all tests
  13. @RegisterExtension
  14. static DemoTestContainer cont = DemoTestContainer.Common.INSTANCE;
  15. static DataManager dataManager;
  16. @BeforeAll
  17. static void beforeAll() {
  18. // Get a bean from the container
  19. dataManager = AppBeans.get(DataManager.class);
  20. }
  21. @Test
  22. void testCreateLoadRemove() {
  23. Customer customer = cont.metadata().create(Customer.class);
  24. customer.setName("c1");
  25. Customer committedCustomer = dataManager.commit(customer);
  26. assertEquals(customer, committedCustomer);
  27. Customer loadedCustomer = dataManager.load(Id.of(customer)).one();
  28. assertEquals(customer, loadedCustomer);
  29. dataManager.remove(loadedCustomer);
  30. }
  31. }

几个有用的测试容器方法

TestContainer 类包含了以下几个方法,可以在测试类里面使用(参考上面的 CustomerTest 例子):

  • persistence() – 返回 Persistence 接口的引用。

  • metadata() – 返回 Metadata 接口的引用。

  • deleteRecord() – 这一组重载方法的目的是在 @After 方法里面使用,在测试完成后清理数据库。

还有,可以按照上面例子中的方法使用 AppBeans.get() 静态方法获取任何 bean。

日志

测试容器根据平台提供的 test-logback.xml 文件来配置日志。

可以通过以下方法配置测试的日志级别:

  • 在项目 core 模块的 test 目录内创建 my-test-logback.xml 文件。

  • my-test-logback.xml 里面配置 appenders 和 loggers。可以从 cuba-core-tests 工件内的 test-logback.xml 文件复制默认的文件内容。

  • 在测试容器里面添加一段静态初始化代码,这段代码通过设置 logback.configurationFile 这个系统属性来指定日志配置文件的位置:

    1. public class DemoTestContainer extends TestContainer {
    2. static {
    3. System.setProperty("logback.configurationFile", "com/company/demo/my-test-logback.xml");
    4. }

附加数据存储

如果项目使用了附加数据存储,并且附加数据库类型与主数据库不同,需要在 build.gradlecore 模块将数据库的驱动添加到 testRuntime 依赖中。示例:

  1. configure(coreModule) {
  2. // ...
  3. dependencies {
  4. // ...
  5. testRuntime(hsql)
  6. jdbc('org.postgresql:postgresql:9.4.1212')
  7. testRuntime('org.postgresql:postgresql:9.4.1212') // add this
  8. }