4.9.2. Web Integration Tests

Web integration tests run in the Spring container of the Web Client block. This test container works independently from the middleware because the framework automatically creates stubs for all middleware services. The testing infrastructure consists of the following classes located in the com.haulmont.cuba.web.testsupport package and nested packages:

  • TestContainer - a wrapper of the Spring container to be used as a base class for project-specific containers.

  • TestServiceProxy - provides default stubs for middleware services. This class can be used to register service mocks specific to a test, see its mock() static method.

  • DataServiceProxy - default stub for DataManager. It contains an implementation for commit() method which mimics the behavior of the real data store: makes new entities detached, increments versions, etc. The loading methods return null and empty collections.

  • TestUiEnvironment - provides a set of methods to configure and obtain TestContainer. Instance of this class should be used in tests as a JUnit 5 extension.

  • TestEntityFactory - convenient factory for creating entity instances for tests. The factory can be obtained from TestContainer.

Although the framework provides default stubs for services, you may want to create your own service mocks in tests. To create mocks, you can use any mocking framework by adding it as a dependency as explained in the section above. Service mocks are registered using the TestServiceProxy.mock() method.

Example of web integration test container

Create test directory in the web module. Then create project’s test container class in an appropriate package of the test directory:

package com.company.demo;

import com.haulmont.cuba.web.testsupport.TestContainer;

import java.util.Arrays;

public class DemoWebTestContainer extends TestContainer {

    public DemoWebTestContainer() {
        appComponents = Arrays.asList(
                "com.haulmont.cuba"
                // add CUBA add-ons and custom app components here
        );
        appPropertiesFiles = Arrays.asList(
                // List the files defined in your web.xml
                // in appPropertiesConfig context parameter of the web module
                "com/company/demo/web-app.properties",
                // Add this file which is located in CUBA and defines some properties
                // specifically for test environment. You can replace it with your own
                // or add another one in the end.
                "com/haulmont/cuba/web/testsupport/test-web-app.properties"
        );
    }

    public static class Common extends DemoWebTestContainer {

        // A common singleton instance of the test container which is initialized once for all tests
        public static final DemoWebTestContainer.Common INSTANCE = new DemoWebTestContainer.Common();

        private static volatile boolean initialized;

        private Common() {
        }

        @Override
        public void before() throws Throwable {
            if (!initialized) {
                super.before();
                initialized = true;
            }
            setupContext();
        }

        @Override
        public void after() {
            cleanupContext();
            // never stops - do not call super
        }
    }
}
Example of UI screen test

Below is an example of web integration test that checks the state of the edited entity after some user action.

package com.company.demo.customer;

import com.company.demo.DemoWebTestContainer;
import com.company.demo.entity.Customer;
import com.company.demo.web.screens.customer.CustomerEdit;
import com.haulmont.cuba.gui.Screens;
import com.haulmont.cuba.gui.components.Button;
import com.haulmont.cuba.gui.screen.OpenMode;
import com.haulmont.cuba.web.app.main.MainScreen;
import com.haulmont.cuba.web.testsupport.TestEntityFactory;
import com.haulmont.cuba.web.testsupport.TestEntityState;
import com.haulmont.cuba.web.testsupport.TestUiEnvironment;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import java.util.Collections;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

public class CustomerEditInteractionTest {

    @RegisterExtension
    TestUiEnvironment environment =
            new TestUiEnvironment(DemoWebTestContainer.Common.INSTANCE).withUserLogin("admin"); (1)

    private Customer customer;

    @BeforeEach
    public void setUp() throws Exception {
        TestEntityFactory<Customer> customersFactory =
                environment.getContainer().getEntityFactory(Customer.class, TestEntityState.NEW);

        customer = customersFactory.create(Collections.emptyMap()); (2)
    }

    @Test
    public void testGenerateName() {
        Screens screens = environment.getScreens(); (3)

        screens.create(MainScreen.class, OpenMode.ROOT).show(); (4)

        CustomerEdit customerEdit = screens.create(CustomerEdit.class); (5)
        customerEdit.setEntityToEdit(customer);
        customerEdit.show();

        assertNull(customerEdit.getEditedEntity().getName());

        Button generateBtn = (Button) customerEdit.getWindow().getComponent("generateBtn"); (6)
        customerEdit.onGenerateBtnClick(new Button.ClickEvent(generateBtn)); (7)

        assertEquals("Generated name", customerEdit.getEditedEntity().getName());
    }
}
1 - define test environment with the shared container and admin user in the user session stub.
2 - create entity instance in the new state.
3 - get Screens infrastructure object from the environment.
4 - open main screen, which is required for opening application screens.
5 - create, initialize and open an entity editor screen.
6 - get Button component.
7 - create a click event and invoke the controller’s method that reacts on the click.
Example of test for loading data in a screen

Below is an example of web integration test that checks the correctness of loaded data.

package com.company.demo.customer;

import com.company.demo.DemoWebTestContainer;
import com.company.demo.entity.Customer;
import com.company.demo.web.screens.customer.CustomerEdit;
import com.haulmont.cuba.core.app.DataService;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.LoadContext;
import com.haulmont.cuba.gui.Screens;
import com.haulmont.cuba.gui.model.InstanceContainer;
import com.haulmont.cuba.gui.screen.OpenMode;
import com.haulmont.cuba.gui.screen.UiControllerUtils;
import com.haulmont.cuba.web.app.main.MainScreen;
import com.haulmont.cuba.web.testsupport.TestEntityFactory;
import com.haulmont.cuba.web.testsupport.TestEntityState;
import com.haulmont.cuba.web.testsupport.TestUiEnvironment;
import com.haulmont.cuba.web.testsupport.proxy.TestServiceProxy;
import mockit.Delegate;
import mockit.Expectations;
import mockit.Mocked;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class CustomerEditLoadDataTest {

    @RegisterExtension
    TestUiEnvironment environment =
            new TestUiEnvironment(DemoWebTestContainer.Common.INSTANCE).withUserLogin("admin"); (1)

    @Mocked
    private DataService dataService; (1)

    private Customer customer;

    @BeforeEach
    public void setUp() throws Exception {
        new Expectations() {{ (2)
            dataService.load((LoadContext<? extends Entity>) any);
            result = new Delegate() {
                Entity load(LoadContext lc) {
                    if ("demo_Customer".equals(lc.getEntityMetaClass())) {
                        return customer;
                    } else
                        return null;
                }
            };
        }};

        TestServiceProxy.mock(DataService.class, dataService); (3)

        TestEntityFactory<Customer> customersFactory =
                environment.getContainer().getEntityFactory(Customer.class, TestEntityState.DETACHED);

        customer = customersFactory.create(
                "name", "Homer", "email", "homer@simpson.com"); (4)
    }

    @AfterEach
    public void tearDown() throws Exception {
        TestServiceProxy.clear(); (5)
    }

    @Test
    public void testLoadData() {
        Screens screens = environment.getScreens();

        screens.create(MainScreen.class, OpenMode.ROOT).show();

        CustomerEdit customerEdit = screens.create(CustomerEdit.class);
        customerEdit.setEntityToEdit(customer);
        customerEdit.show();

        InstanceContainer customerDc = UiControllerUtils.getScreenData(customerEdit).getContainer("customerDc"); (6)
        assertEquals(customer, customerDc.getItem());
    }
}
1 - define data service mock using JMockit framework.
2 - define the mock behavior.
3 - register the mock.
4 - create entity instance in the detached state.
5 - remove the mock after the test completes.
6 - get data container.