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.

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 the CustomerTest 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 the test folder of your project’s core module.

  • Configure appenders and loggers in my-test-logback.xml. You can take the default content from the test-logback.xml file located inside the cuba-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 the core module in build.gradle, for example:

configure(coreModule) {
    // ...
    dependencies {
        // ...
        testRuntime(hsql)
        jdbc('org.postgresql:postgresql:9.4.1212')
        testRuntime('org.postgresql:postgresql:9.4.1212') // add this
    }