5.7.2. Интеграционные тесты Middleware
На уровне Middleware можно создавать интеграционные тесты, которые выполняются в полнофункциональном контейнере Spring с подключением к базе данных. В тестах такого типа можно выполнять код любого слоя внутри Middleware - от сервисов до ORM.
Для того, чтобы выполнять тесты из IDE, создайте каталог test
в модуле core рядом с src
. После этого пересоздайте проектные файлы IDE.
Платформа содержит класс TestContainer
, который может быть использован в качестве базового для тестовых контейнеров приложения. Создайте наследника этого класса в каталоге test
модуля core и в его конструкторе переопределите параметры загрузки компонентов и свойств приложения, а также параметры подключения к тестовой БД. Например:
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
"cuba-app.properties",
"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.
"test-app.properties");
dbDriver = "org.postgresql.Driver";
dbUrl = "jdbc:postgresql://localhost/sales_test";
dbUser = "cuba";
dbPassword = "cuba";
}
}
В качестве базы данных рекомендуется использовать отдельную тестовую БД, которую можно создавать, например, следующей задачей в 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
:
public class CustomerLoadTest {
@ClassRule
public static SalesTestContainer cont = new SalesTestContainer();
private Customer customer;
@Before
public void setUp() throws Exception {
customer = cont.persistence().createTransaction().execute(em -> {
Customer customer = new Customer();
customer.setName("testCustomer");
em.persist(customer);
return customer;
});
}
@After
public void tearDown() throws Exception {
cont.deleteRecord(customer);
}
@Test
public void test() {
try (Transaction tx = cont.persistence().createTransaction()) {
EntityManager em = cont.persistence().getEntityManager();
TypedQuery<Customer> query = em.createQuery(
"select c from sales$Customer c", Customer.class);
List<Customer> list = query.getResultList();
tx.commit();
assertTrue(list.size() > 0);
}
}
}
В данном примере тестовый контейнер инициализируется один раз для всех тестовых методов класса, и уничтожается после того, как все они выполнены.
Так как запуск контейнера занимает некоторое время, имеет смысл инициализировать контейнер один раз для тестов из нескольких (или всех) классов. Для этого создайте общий синглтон-экземпляр тестового контейнера, например:
public class SalesTestContainer extends TestContainer {
public SalesTestContainer() {
...
}
public static class Common extends SalesTestContainer {
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
}
}
}
И используйте его в тестовых классах:
public class CustomerLoadTest {
@ClassRule
public static SalesTestContainer cont = SalesTestContainer.Common.INSTANCE;
...
}
Класс TestContainer
содержит следующие методы, которые можно использовать в коде тестов (см. пример CustomerLoadTest
выше):
-
persistence()
- возвращает ссылку на интерфейсPersistence
. -
metadata()
- возвращает ссылку на интерфейсMetadata
. -
deleteRecord()
- этот набор перегруженных методов предназначен для использования в@After
методах для удаления тестовых объектов из БД.