4.8.1. Интеграционные тесты Middleware
Интеграционные тесты Middleware выполняются в полнофункциональном контейнере Spring с подключением к базе данных. В тестах такого типа можно выполнять код любого слоя внутри Middleware - от сервисов до ORM.
Для конфигурирования и запуска контейнера Spring в тестах среднего слоя создайте в приложении наследника базовового класса com.haulmont.cuba.testsupport.TestContainer
и используйте его экземпляр в тестах в качестве JUnit Rule.
Ниже приведен пример класса контейнера и интеграционного теста для проекта Sales, описанного в разделе Быстрый старт. Все классы должны находится в каталоге test
модуля core
.
package com.company.sales;
import com.haulmont.cuba.testsupport.TestContainer;
import java.util.ArrayList;
import java.util.Arrays;
public class SalesTestContainer extends TestContainer {
public SalesTestContainer() {
super();
appComponents = new ArrayList<>(Arrays.asList(
"com.haulmont.cuba"
// add CUBA premium add-ons here
// "com.haulmont.bpm",
// "com.haulmont.charts",
// "com.haulmont.fts",
// "com.haulmont.reports",
// and custom app components if any
));
appPropertiesFiles = Arrays.asList(
// List the files defined in your web.xml
// in appPropertiesConfig context parameter of the core module
"com/company/sales/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/testsupport/test-app.properties");
initDbProperties();
}
private void initDbProperties() {
dbDriver = "org.postgresql.Driver";
dbUrl = "jdbc:postgresql://localhost/sales_test";
dbUser = "cuba";
dbPassword = "cuba";
}
public static class Common extends SalesTestContainer {
// A common singleton instance of the test container which is initialized once for all tests
public static final SalesTestContainer.Common INSTANCE = new SalesTestContainer.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
}
}
}
Пример собственного файлв test-app.properties
:
cuba.webContextName = app-core
sales.someProperty = someValue
В качестве базы данных рекомендуется использовать отдельную тестовую БД, которую можно создавать, например, следующей задачей в build.gradle
:
configure(coreModule) {
...
task createTestDb(dependsOn: assemble, description: 'Creates local Postgres database for tests', type: CubaDbCreation) {
dbms = 'postgres'
dbName = 'sales_test'
dbUser = 'cuba'
dbPassword = 'cuba'
}
Тестовый контейнер используется в классах тестов в качестве JUnit rule, указанного с помощью аннотации @ClassRule
:
package com.company.sales;
import com.company.sales.entity.Customer;
import com.haulmont.cuba.core.global.*;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
public class CustomerTest {
// Using the common singleton instance of the test container which is initialized once for all tests
@ClassRule
public static SalesTestContainer cont = SalesTestContainer.Common.INSTANCE;
private Metadata metadata;
@Before
public void setUp() throws Exception {
metadata = cont.metadata();
}
@Test
public void testCreateCustomer() throws Exception {
// Get a managed bean (or service) from container
DataManager dataManager = AppBeans.get(DataManager.class);
// Create new Customer
Customer customer = metadata.create(Customer.class);
customer.setName("Test customer");
// Save the customer to the database
dataManager.commit(customer);
// Load the customer by ID
Customer loaded = dataManager.load(
LoadContext.create(Customer.class).setId(customer.getId()).setView(View.LOCAL));
assertNotNull(loaded);
assertEquals(customer.getName(), loaded.getName());
// Remove the customer
dataManager.remove(loaded);
}
}
- Полезные методы тестового контейнера
-
Класс
TestContainer
содержит следующие методы, которые можно использовать в коде тестов (см. примерCustomerLoadTest
выше):-
persistence()
- возвращает ссылку на интерфейс Persistence. -
metadata()
- возвращает ссылку на интерфейс Metadata. -
deleteRecord()
- этот набор перегруженных методов предназначен для использования в@After
методах для удаления тестовых объектов из БД.
-
- Логирование
-
Класс
TestContainer
настраивает логирование в соответствие с файломtest-logback.xml
, предоставляемым платформой. Данный файл содержится в артефактеcuba-core-tests
.Для того, чтобы настроить уровни логирования в своих тестах, необходимо выполнить следующее:
-
Скопируйте файл
test-logback.xml
из артефакта платформы в корень каталогаtest
модуляcore
проекта, например какmy-test-logback.xml
. -
Сконфигурируйте параметры логирования в
my-test-logback.xml
. -
Добавьте блок статической инициализации в класс тестового контейнера проекта и укажите местоположение файла конфигурации Logback в системном свойстве
logback.configurationFile
:public class MyTestContainer extends TestContainer { static { System.setProperty("logback.configurationFile", "my-test-logback.xml"); } // ... }
-
- Дополнительные хранилища
-
Если в вашем проекте используются дополнительные хранилища, необходимо создать соответствующие источники данных JDBC в тестовом контейнере. Например, если у вас есть хранилище
mydb
, являющееся базой данных PostgreSQL, добавьте следующий метод в класс тестового контейнера:public class MyTestContainer extends TestContainer { // ... @Override protected void initDataSources() { super.initDataSources(); try { Class.forName("org.postgresql.Driver"); TestDataSource mydbDataSource = new TestDataSource( "jdbc:postgresql://localhost/mydatabase", "db_user", "db_password"); TestContext.getInstance().bind( AppContext.getProperty("cuba.dataSourceJndiName_mydb"), mydbDataSource); } catch (ClassNotFoundException | NamingException e) { throw new RuntimeException("Error initializing datasource", e); } } }
Кроме того, если тип дополнительной базы данных отличается от основной, необходимо добавить ее драйвер как
testRuntime
зависимость модуляcore
вbuild.gradle
, например:configure(coreModule) { // ... dependencies { // ... testRuntime(hsql) jdbc('org.postgresql:postgresql:9.4.1212') testRuntime('org.postgresql:postgresql:9.4.1212') // add this }