4.8.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 itsmock()
static method. -
DataServiceProxy
- default stub forDataManager
. It contains an implementation forcommit()
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 obtainTestContainer
. Instance of this class should be used in tests as a JUnit Rule. -
TestEntityFactory
- convenient factory for creating entity instances for tests. The factory can be obtained fromTestContainer
.
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 theweb
module. Then create project’s test container class in an appropriate package of thetest
directory:package com.company.sales.web; import com.haulmont.cuba.web.testsupport.TestContainer; import java.util.ArrayList; import java.util.Arrays; public class SalesWebTestContainer extends TestContainer { public SalesWebTestContainer() { appComponents = new ArrayList<>(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/sales/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 SalesWebTestContainer { // A common singleton instance of the test container which is initialized once for all tests public static final SalesWebTestContainer.Common INSTANCE = new SalesWebTestContainer.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.sales.web.customer; import com.company.sales.entity.Customer; import com.company.sales.web.SalesWebTestContainer; 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.Before; import org.junit.Rule; import org.junit.Test; import java.util.Collections; import static org.junit.Assert.*; public class CustomerEditInteractionTest { @Rule public TestUiEnvironment environment = new TestUiEnvironment(SalesWebTestContainer.Common.INSTANCE).withUserLogin("admin"); (1) private Customer customer; @Before 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.sales.web.customer; import com.company.sales.entity.Customer; import com.company.sales.web.SalesWebTestContainer; 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.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import static org.junit.Assert.assertEquals; public class CustomerEditLoadDataTest { @Rule public TestUiEnvironment environment = new TestUiEnvironment(SalesWebTestContainer.Common.INSTANCE).withUserLogin("admin"); @Mocked private DataService dataService; (1) private Customer customer; @Before public void setUp() throws Exception { new Expectations() {{ (2) dataService.load((LoadContext<? extends Entity>) any); result = new Delegate() { Entity load(LoadContext lc) { if ("sales_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) } @After 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.