Как протестировать источник данных, введенный с помощью @Resource

#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, серверу приложений.