4.9.1. Middleware Integration Tests
Middleware integration tests run in a fully functional Spring container connected to the database. In such tests, you can run code on all layers of the middleware, from services down to ORM.
|
See also Middleware Integration Testing in CUBA Applications guide. |
Right after creating a new project in Studio, you can find two classes in the base package of the core module: a test container class and a sample test. The test container class launches the middleware Spring container which is set up for tests. The sample test makes use of it and demonstrates how to test some operations with an entity.
Let’s consider the generated test container class and how it should be adapted to your needs.
The class must extend TestContainer provided by CUBA. In the constructor, you should do the following:
-
Add application components (add-ons) used in your project to the
appComponentslist. -
If needed, specify additional application properties files in the
appPropertiesFileslist. -
Invoke the
autoConfigureDataSource()method to initialize the test data source using the information from application properties or context.xml.
The generated test container provides connection to the same database as used by the application, so your tests will work against your main data store even if you change its type or how the JDBC DataSource is defined.
There is a disadvantage of using the same database for tests and for the application: the data entered manually may interfere with test data and break test execution. To avoid this, you can set up a separate database and use it only for tests. We recommend using a test database of the same type as your main database in order to use the same set of database migration scripts. Below is an example of setting up a test database on local PostgreSQL.
First, add the test database creation task to build.gradle:
configure(coreModule) {
// ...
task createTestDb(dependsOn: assembleDbScripts, type: CubaDbCreation) {
dbms = 'postgres'
host = 'localhost'
dbName = 'demo_test'
dbUser = 'cuba'
dbPassword = 'cuba'
}
Then create the test-app.properties file in the base package of the test sources root (e.g. modules/core/test/com/company/demo/test-app.properties) and specify the test database connection properties:
cuba.dataSource.host = localhost
cuba.dataSource.dbName = demo_test
cuba.dataSource.username = cuba
cuba.dataSource.password = cuba
Add this file to the appPropertiesFiles list of the test container:
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();
}
Before running tests, create the test database by executing the task:
./gradlew createTestDb
The test container should be used in test classes as a JUnit 5 extension specified by the @RegisterExtension annotation:
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);
}
}
- Useful container methods
-
The
TestContainerclass has the following methods that can be used in the test code (see theCustomerTestexample above):-
persistence()– returns the reference to the Persistence interface. -
metadata()– returns the reference to the Metadata interface. -
deleteRecord()– this set of overloaded methods is aimed to be used in@Aftermethods to clean up the database after tests.
Besides, you can obtain any bean using the
AppBeans.get()static method as shown in the example above. -
- Logging
-
The test container sets up logging according to the
test-logback.xmlfile provided by the platform.If you want to configure logging levels for your tests, do the following:
-
Create
my-test-logback.xmlfile in thetestfolder of your project’scoremodule. -
Configure appenders and loggers in
my-test-logback.xml. You can take the default content from thetest-logback.xmlfile located inside thecuba-core-testsartifact. -
Add a static initializer to your test container to specify the location of your logback configuration file in the
logback.configurationFilesystem property:public class DemoTestContainer extends TestContainer { static { System.setProperty("logback.configurationFile", "com/company/demo/my-test-logback.xml"); }
-
- Additional Data Stores
-
If your project uses additional data stores and the additional database type is different from the main one, you should add its driver as the
testRuntimedependency to thecoremodule inbuild.gradle, for example:configure(coreModule) { // ... dependencies { // ... testRuntime(hsql) jdbc('org.postgresql:postgresql:9.4.1212') testRuntime('org.postgresql:postgresql:9.4.1212') // add this }