Этот пост был написан вместе с + 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/
Ссылка: | Тестирование с пришельцами: Как протестировать преобразователь типов JPA с помощью Arquillian от нашего партнера по JCG Торбена Янссена в блоге » Некоторые мысли о Java (EE)» . |