4.9.1. 中间件集成测试
中间件继承测试运行在具有完整功能的 Spring 容器里,而且可以连接数据库。在这些测试类里面,可以运行中间件里面各细分层的代码,比如从 ORM 层到 Service 层。
Studio 创建新项目之后,可以在 core
模块的包内找到两个类:一个测试容器类和一个测试示例类。测试容器类会启动中间件的 Spring 容器,该容器用来做测试。测试示例类使用这个容器并演示如何用实体测试一些操作。
我们看看生成的测试容器类,怎么能满足我们的需求。
该类必须继承 CUBA 提供的 TestContainer
类。在构造器中,需要做下面这些事:
需要在
appComponents
列表中添加项目中使用的 应用程序组件(扩展插件)。如果需要,在
appPropertiesFiles
列表指定附加的应用程序属性文件。调用
autoConfigureDataSource()
方法使用来自应用程序属性或者 context.xml 的信息初始化测试数据源。
生成的测试容器会提供与应用程序相同的数据库连接,所以即使修改了类型或者 JDBC 数据源的定义,测试用例还是会使用主数据存储运行。
使用同一个数据库进行测试和运行应用程序有一个弊端:手动输入的数据会干扰测试数据并有可能破坏测试用例的执行。避免的方法就是为测试单独配置一个数据库。我们建议使用和主数据存储同类型的数据库作为测试数据库,以便使用同一组 数据库迁移脚本。下面是在本地 PostgreSQL 配置测试数据库的一个示例。
首先,在 build.gradle
添加测试数据库创建的 任务:
configure(coreModule) {
// ...
task createTestDb(dependsOn: assembleDbScripts, type: CubaDbCreation) {
dbms = 'postgres'
host = 'localhost'
dbName = 'demo_test'
dbUser = 'cuba'
dbPassword = 'cuba'
}
然后在测试源码的根包(比如 modules/core/test/com/company/demo/test-app.properties
)内创建 test-app.properties
文件,并制定测试数据库的连接属性:
cuba.dataSource.host = localhost
cuba.dataSource.dbName = demo_test
cuba.dataSource.username = cuba
cuba.dataSource.password = cuba
添加该文件至测试容器的 appPropertiesFiles
列表:
public class DemoTestContainer extends TestContainer {
public DemoTestContainer() {
super();
appComponents = Arrays.asList(
"com.haulmont.cuba"
);
appPropertiesFiles = Arrays.asList(
"com/company/demo/app.properties",
"com/haulmont/cuba/testsupport/test-app.properties",
"com/company/demo/test-app.properties" // your test properties
);
autoConfigureDataSource();
}
运行测试用例之前,执行这个任务创建测试数据库:
./gradlew createTestDb
这个测试容器应当在测试类里面作为 @RegisterExtension
注解指定的 JUnit 5 扩展:
package com.company.demo.core;
import com.company.demo.DemoTestContainer;
import com.company.demo.entity.Customer;
import com.haulmont.cuba.core.entity.contracts.Id;
import com.haulmont.cuba.core.global.AppBeans;
import com.haulmont.cuba.core.global.DataManager;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CustomerTest {
// Using the common singleton instance of the test container which is initialized once for all tests
@RegisterExtension
static DemoTestContainer cont = DemoTestContainer.Common.INSTANCE;
static DataManager dataManager;
@BeforeAll
static void beforeAll() {
// Get a bean from the container
dataManager = AppBeans.get(DataManager.class);
}
@Test
void testCreateLoadRemove() {
Customer customer = cont.metadata().create(Customer.class);
customer.setName("c1");
Customer committedCustomer = dataManager.commit(customer);
assertEquals(customer, committedCustomer);
Customer loadedCustomer = dataManager.load(Id.of(customer)).one();
assertEquals(customer, loadedCustomer);
dataManager.remove(loadedCustomer);
}
}
几个有用的测试容器方法
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
这个系统属性来指定日志配置文件的位置:public class DemoTestContainer extends TestContainer {
static {
System.setProperty("logback.configurationFile", "com/company/demo/my-test-logback.xml");
}
附加数据存储
如果项目使用了附加数据存储,并且附加数据库类型与主数据库不同,需要在 build.gradle
的 core
模块将数据库的驱动添加到 testRuntime
依赖中。示例:
configure(coreModule) {
// ...
dependencies {
// ...
testRuntime(hsql)
jdbc('org.postgresql:postgresql:9.4.1212')
testRuntime('org.postgresql:postgresql:9.4.1212') // add this
}