#jakarta-ee #java-ee-6 #java-ee-7 #jboss-arquillian #java-ee-8
#джакарта-ee #java-ee-6 #java-ee-7 #jboss-arquillian #java-ee-8
Вопрос:
Я хочу создать несколько интеграционных тестов для следующего класса:
public class MyDao {
@Inject
@Postgres
private DataSource dataSource;
getSomething() {
//do something with dataSource
}
}
У меня есть квалификатор:
@Qualifier
@Target({ TYPE, METHOD, FIELD, PARAMETER })
@Retention(RUNTIME)
public @interface Postgres {
}
А также у меня есть продюсер:
public class PostgresDataSourceProducer {
@Resource(mappedName = "java:jboss/PostgresDS")
private DataSource ds;
@Produces
@Postgres
DataSource postgresDataSouce() {
return ds;
}
}
Я использую wildfly 14. Источник данных был определен в standalone.xml:
<subsystem xmlns="urn:jboss:domain:datasources:5.0">
<datasources>
<datasource jta="false" jndi-name="java:jboss/PostgresDS" pool-name="postgres" enabled="true" use-ccm="false">
<connection-url>jdbc:postgresql://${production.postgres.url}</connection-url>
<driver-class>org.postgresql.Driver</driver-class>
<driver>postgresql-8.0-310.jdbc3.jar</driver>
<security>
<user-name>${db.username}</user-name>
<password>${db.userpass}</password>
</security>
<validation>
<validate-on-match>false</validate-on-match>
<background-validation>false</background-validation>
</validation>
<statement>
<share-prepared-statements>false</share-prepared-statements>
</statement>
</datasource>
</datasources>
</subsystem>
Для создания интеграционных тестов мне нужно будет изменить источник данных, чтобы он указывал на мою тестовую базу данных. Как это сделать?
Поскольку это устаревший код, я зарезервирован для переключения с @Resource
на @PersistenceContext
.
Ответ №1:
Есть много способов сделать это, но сначала определите свой тестовый источник данных в подсистеме (давайте сопоставим его с java:jboss/H2
ради приведенных ниже примеров).
Через CDI @Alternative
Создайте другой класс производителя для тестового источника данных и пометьте его как альтернативу.
Пример:
public class PostgresDataSourceProducer {
@Resource(mappedName = "java:jboss/PostgresDS")
private DataSource primary;
}
@Alternative
public class H2DataSourceProducer {
@Resource(mappedName = "java:jboss/H2")
private DataSource test;
}
В каталоге тестовых ресурсов добавьте новый файл дескриптора CDI специально для тестов. Возможно, вы захотите скопировать конфигурации из основного файла дескриптора, чтобы сохранить поведение или избежать ошибок во время выполнения.
Пример:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="all">
<alternatives>
<class>path.to.your.datasource.H2DataSourceProducer</class>
</alternatives>
</beans>
И, наконец, при создании тестовых артефактов через Shrinkwrap
замените файлы дескрипторов CDI для затронутых модулей на указанные выше.
Пример:
final var services = ...;
services.addAsManifestResource("META-INF/beans.xml", "beans.xml");
Через конфигурацию JPA Persistence-unit
Вы также можете просто очистить производителя источника данных и позволить JPA получить правильный источник данных во время выполнения через конфигурацию модуля сохранения.
Добавьте новый persistence.xml
файл в каталог тестовых ресурсов. Сохраните все из основной конфигурации сохранения, за исключением свойства источника данных.
Пример:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
version="2.2">
<persistence-unit name="primary">
<!--<jta-data-source>java:jboss/PostgresDS</jta-data-source>-->
<jta-data-source>java:jboss/H2</jta-data-source>
...
</persistence-unit>
</persistence>
И, наконец, при создании ваших тестовых артефактов через Shrinkwrap
, замените основной файл конфигурации сохранения на приведенный выше.
Комментарии:
1. Предполагая, что производители производят с помощью квалификатора
@Produces @PostgresQualifier public Datasource producePostgres()
и@Produces @H2Qualifier public Datasource produceH2()
. Какой тип имеет параметр, если я хочу внедрить конструктор? Они не реализуют один и тот же интерфейс. Например, этот конструктор:@Inject public MyClass(@PostgresQualifier/@H2Qualifier Datasource ds){.....}
.2. Зачем вам это делать? В представленном мной решении контейнер будет создавать тестовый источник данных только тогда, когда производитель активирован в файле дескриптора CDI, и это только при запуске тестов после замены файла.
3. Да, я согласен с вами. На мой взгляд, предоставленное вами решение лучше всего подходит для интеграционного тестирования. Тем не менее, я не вижу, чтобы это применимо для модульного тестирования. В некоторых не столь сложных тестовых сценариях я предпочитаю издеваться над сотрудником. Если возможно что-то близкое к тому, о чем я спрашивал в моем предыдущем комментарии, то вы можете выполнить как модульное тестирование с помощью mocks, так и интеграционный тест.
4. На вашем месте я бы не создавал модульные тесты с использованием Arquillian. Модульные тесты предположительно предназначены для тестирования отдельных компонентов или функций, поэтому они должны быть выполнимы с помощью чисто имитирующих зависимостей, чтобы легко устанавливать заданные условия для получения правильных результатов. Arquillian лучше всего подходит для интеграции и функционального тестирования. При этом я считаю, что представленный мной ответ правильный и должен соответствовать вашим требованиям.
5. Задавая ожидаемый тип, вы имеете в виду тип среды выполнения источника данных, который вводит контейнер? Если да, то зачем вам это знать? Разве вы не использовали JPA / Hibernate? Разве вы не использовали Wildfly / JBoss для настройки контекста сохранения? Почему приложению все еще нужен источник данных в первую очередь? На вашем месте я бы доверил все источники данных или материалы, связанные с JPA, серверу приложений.