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
appComponents
list. -
If needed, specify additional application properties files in the
appPropertiesFiles
list. -
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
TestContainer
class has the following methods that can be used in the test code (see theCustomerTest
example 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@After
methods 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.xml
file provided by the platform.If you want to configure logging levels for your tests, do the following:
-
Create
my-test-logback.xml
file in thetest
folder of your project’score
module. -
Configure appenders and loggers in
my-test-logback.xml
. You can take the default content from thetest-logback.xml
file located inside thecuba-core-tests
artifact. -
Add a static initializer to your test container to specify the location of your logback configuration file in the
logback.configurationFile
system 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
testRuntime
dependency to thecore
module 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 }