Статьи

Тестирование с пришельцами: Как проверить преобразователь типа JPA с Arquillian

Этот пост был написан вместе с + Aslak Knutsen ( @aslakknutsen ).

Преобразователи типов JPA предоставляют простой способ определить, как атрибут сущности сохраняется в базе данных. Вы можете использовать их для реализации множества различных функций, например, для шифрования ваших данных, как я показал в предыдущем посте: Как использовать JPA Type Converter для шифрования ваших данных .

Но написание конвертера типов недостаточно. Мы также должны убедиться, что он работает правильно.

В общем, есть два способа проверить преобразователь типов. Мы могли бы написать модульный тест, чтобы проверить, правильно ли работает преобразование. Но модульный тест выполняет тест изолированного класса, не помещая его в реальную среду выполнения. Это означает, что мы до сих пор не узнаем, работает ли конвертер в одном из наших приложений. Если все настроено правильно, поставщик сохраняемости вызовет конвертер перед записью в базу данных и после нее. Поэтому нам также необходимо проверить, вызывается ли преобразователь типа поставщиком постоянства и все ли работает нормально в этом состоянии. Нам нужно протестировать конвертер внутри контейнера, который мы хотим использовать для нашего приложения.

Мы посмотрим, как это можно сделать с помощью Arquillian и его продления.

Что-то об Аркиллиане

Если вы уже знакомы с Arquillian, вы можете пропустить эту часть. Для всех вас, кто до сих пор не работал с Arquillian, я просто хочу дать некоторую основную информацию. Вы можете найти более подробное описание в руководстве по началу работы с Arquillian .

Arquillian — это тестовая среда для тестирования контейнеров. Идея состоит в том, чтобы не издеваться над контейнером, который вы хотите использовать, а для проверки вашего кода внутри него. Это дает преимущество в том, что вы можете проверить, будет ли ваш код работать и в вашей среде выполнения, а не только в вашем тестовом сценарии. Arquillian предоставляет множество функций для управления контейнером, внедрения необходимых ресурсов, таких как EJB или EntityManager, и упрощения вашей жизни.

Тесты Arquillian выполнены junit. Это здорово, потому что вы можете использовать их везде, где вы можете выполнять тесты junit. И это означает, что в вашей среде IDE, как части вашего процесса сборки, на вашем CI-сервере, просто везде.

Тестируемый объект

Следующий фрагмент кода показывает тестируемый объект для этого примера. Это конвертер типов, который шифрует и дешифрует атрибут String. Преобразователь вызывается поставщиком сохраняемости перед записью в базу данных и после нее. Если вы хотите узнать больше о том, как работает этот конвертер типов, проверьте мою публикацию об этом .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Converter
public class CryptoConverter implements AttributeConverter<String, String> {
 
    private static final String ALGORITHM = "AES/ECB/PKCS5Padding";
    private static final byte[] KEY = "MySuperSecretKey".getBytes();
 
    @Override
    public String convertToDatabaseColumn(String ccNumber) {
      // do some encryption
      Key key = new SecretKeySpec(KEY, "AES");
      try {
         Cipher c = Cipher.getInstance(ALGORITHM);
         c.init(Cipher.ENCRYPT_MODE, key);
         return Base64.encodeBytes(c.doFinal(ccNumber.getBytes()));
      } catch (Exception e) {
         throw new RuntimeException(e);
      }
    }
 
    @Override
    public String convertToEntityAttribute(String dbData) {
      // do some decryption
      Key key = new SecretKeySpec(KEY, "AES");
      try {
        Cipher c = Cipher.getInstance(ALGORITHM);
        c.init(Cipher.DECRYPT_MODE, key);
        return new String(c.doFinal(Base64.decode(dbData)));
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }
}

Настройка его

Прежде чем мы сможем начать писать наши тесты, нам нужно определить несколько зависимостей. Я покажу только, как настроить зависимости, которые нам нужны для этого примера. Если вы еще не настроили тесты Arquillian для своего проекта, вам придется сделать немного больше. Пожалуйста, ознакомьтесь с руководством по началу работы, чтобы узнать, как настроить arquillian для вашего проекта. Не бойся, здесь не так уж много дел.

Как вы можете видеть в следующем фрагменте, мы будем использовать JUnit 4.11 , Arquillian 1.1.3.Final , Arquillian Persistence Extension 1.0.0.Alpha7 и сервер приложений WildFly 8.1.0.Final .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?xml version="1.0" encoding="UTF-8"?>
<project
     
    ...
 
    <properties>
        <version.junit>4.11</version.junit>
        <version.arquillian>1.1.3.Final</version.arquillian>
        <version.arquillian_persistence>1.0.0.Alpha7</version.arquillian_persistence>
        <version.wildfly>8.1.0.Final</version.wildfly>
    </properties>
 
    <dependencyManagement>
        <dependencies>
            ...
            <dependency>
                <groupId>org.jboss.arquillian</groupId>
                <artifactId>arquillian-bom</artifactId>
                <version>${version.arquillian}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
 
    <dependencies>
        ...
        <dependency>
            <groupId>javax.enterprise</groupId>
            <artifactId>cdi-api</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${version.junit}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.arquillian.junit</groupId>
            <artifactId>arquillian-junit-container</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.arquillian.extension</groupId>
            <artifactId>arquillian-persistence-dbunit</artifactId>
            <version>${version.arquillian_persistence}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

Написание тестов

Для настройки нашей тестовой среды нам нужно сделать две вещи. Сначала нам нужно сообщить junit, что этот тест должен выполняться как тест junit. Это делается @RunWith(Arquillian.class) .

Кроме того, нам нужно создать тестовое развертывание, которое будет развернуто в контейнере. Поэтому нам нужно реализовать хотя бы один метод и аннотировать его с помощью @Deployment . Как вы можете видеть в следующем фрагменте кода, мы используем ShrinkWrap для создания развертывания jar-архива. Архив содержит сущность CryptoConverter конвертер типов CryptoConverter и тестовый класс. Нет необходимости включать какие-либо EJB или другие классы, которые реализуют бизнес-логику. Мы можем внедрить EntityManager в наш тестовый пример и использовать его напрямую для сохранения и чтения сущностей. Мы более подробно рассмотрим это позже.

Кроме того, нам нужно добавить некоторые ресурсы манифеста для создания модуля персистентности, зарегистрировать конвертер типов и добавить пустой файл beans.xml для активации CDI. Пожалуйста, ознакомьтесь с руководством по началу работы, чтобы получить больше информации о ShrinkWrap и создании развертываний.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
@RunWith(Arquillian.class)
public class TestCryptoConverter {
 
    @Deployment
    public static JavaArchive createDeployment() {
        return ShrinkWrap
                .create(JavaArchive.class)
                .addClasses(CreditCard.class, CryptoConverter.class,
                        TestCryptoConverter.class)
                .addAsManifestResource("META-INF/persistence.xml",
                        "persistence.xml")
                .addAsManifestResource("META-INF/orm.xml", "orm.xml")
                .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
    }

После того, как это сделано, мы можем начать писать тестовые случаи. Сначала мы CreditCard сущность CreditCard и проверим, шифруется ли номер кредитной карты CryptoConverter . Поэтому мы внедряем EntityManager, создаем сущность CreditCard и передаем ее в метод persist EntityManager. Проверка постоянных данных выполняется расширением постоянства Аркиллиана. Нам просто нужно определить данные, которые мы ожидаем записать в базу данных. Ожидаемые данные определены в файле cc.yml, на который есть ссылка в аннотации @ShouldMatchDataSet . Поскольку атрибут id генерируется базой данных, мы хотим исключить его из проверки. Это может быть сделано путем ссылки на него в атрибуте excludeColumns аннотации.

01
02
03
04
05
06
07
08
09
10
11
12
@PersistenceContext
    private EntityManager em;
 
    @Test
    @ShouldMatchDataSet(value = "data/cc.yml", excludeColumns = "id")
    public void testEncryption() {
        CreditCard cc = new CreditCard();
        cc.setName("My Name");
        cc.setCcNumber("123456789");
 
        this.em.persist(cc);
    }

Cc.yml содержит следующую информацию.

1
2
3
4
CreditCard:
  - id: 1
    name: My Name
    ccNumber: egFfkhd8cRh82tvsh3VVUg==

Во втором тесте мы проверим, можем ли мы искать в базе данных объект CreditCard с указанным номером кредитной карты. Поэтому мы используем аннотацию @UsingDataSet для @UsingDataSet базы данных данными, определенными в файле cc.yml. Теперь мы можем использовать введенный EntityManager для вызова именованного запроса для поиска объекта CreditCard с заданным номером.

1
2
3
4
5
6
7
8
@Test
    @UsingDataSet("data/cc.yml")
    public void testRead() {
        CreditCard cc = this.em
                .createNamedQuery(CreditCard.BY_NUMBER, CreditCard.class)
                .setParameter("number", "123456789").getSingleResult();
        Assert.assertEquals("My Name", cc.getName());
    }

Вывод

Мы использовали Arquillian и расширение Arquillian Persistence для тестирования преобразователя типов JPA. Поэтому мы @ShouldMatchData EntityManager и использовали аннотации @ShouldMatchData и @UsingDataSet для проверки и @UsingDataSet базы данных файлом yml.

Если вы хотите попробовать это сами, вы можете найти источники на github .
Вы можете запустить его, вызвав: git clone https://github.com/thjanssen/JPA2.1.git && cd JPA2.1 / CryptoConverter && mvn test.

Каков ваш опыт тестирования приложения Java EE с Arquillian? Пожалуйста, напишите комментарий об этом.
Хотите узнать больше об Arquillian, посмотрите Arquillian Guides: http://arquillian.org/guides/