1. Обзор
Как правило, при тестировании приложения, использующего JNDI, мы можем использовать поддельный источник данных вместо реального. Это обычная практика при тестировании, чтобы сделать наши модульные тесты простыми и полностью отделенными от любого внешнего контекста.
В этом уроке мы продемонстрируем, как протестировать макет источника данных JNDI с помощью Spring Framework и библиотеки Simple-JNDI.
В этом уроке мы сосредоточимся только на модульных тестах. Но обязательно ознакомьтесь с нашей статьей о том, как создать приложение Spring с использованием JPA с источником данных JNDI .
2. Быстрый обзор JNDI
Короче говоря, JNDI связывает логические имена с внешними ресурсами, такими как соединения с базой данных . Основная идея заключается в том, что приложению не нужно ничего знать об определенном источнике данных, кроме его имени JNDI.
Проще говоря, все операции именования связаны с контекстом, поэтому, чтобы использовать JNDI для доступа к службе именования, нам сначала нужно создать объект InitialContext . Как следует из названия, InitialContext class инкапсулирует начальный (корневой) контекст, который обеспечивает отправную точку для операций именования.
Проще говоря, корневой контекст действует как точка входа. Без этого JNDI не сможет найти или просмотреть наши ресурсы.
3. Как протестировать источник данных JNDI с помощью Spring
Spring обеспечивает встроенную интеграцию с JNDI через SimpleNamingContextBuilder . Этот вспомогательный класс предлагает отличный способ издеваться над средой JNDI для целей тестирования.
Итак, давайте посмотрим, как мы можем использовать класс SimpleNamingContextBuilder для модульного тестирования источника данных JNDI.
Во-первых, нам нужно создать начальный контекст именования для привязки и извлечения объекта источника данных :
@BeforeEach public void init() throws Exception { SimpleNamingContextBuilder.emptyActivatedContextBuilder(); this.initContext = new InitialContext(); }
Мы создали корневой контекст с помощью метода emptyActivatedContextBuilder () , поскольку он обеспечивает большую гибкость по сравнению с конструктором, поскольку он создает новый конструктор или возвращает существующий.
Теперь, когда у нас есть контекст, давайте реализуем модульный тест, чтобы увидеть, как хранить и извлекать объект JDBC DataSource с помощью JNDI:
@Test public void whenMockJndiDataSource_thenReturnJndiDataSource() throws Exception { this.initContext.bind("java:comp/env/jdbc/datasource", new DriverManagerDataSource("jdbc:h2:mem:testdb")); DataSource ds = (DataSource) this.initContext.lookup("java:comp/env/jdbc/datasource"); assertNotNull(ds.getConnection()); }
Как мы видим , мы используем метод bind() для сопоставления нашего объекта JDBC DataSource с именем java:comp/env/jdbc/datasource .
Затем мы используем метод lookup() для извлечения ссылки DataSource из нашего контекста JNDI, используя точное логическое имя, которое мы использовали ранее для привязки объекта JDBC DataSource .
Обратите внимание, что JNDI просто выдаст исключение в случае, если указанный объект не найден в контексте.
Стоит отметить, что класс SimpleNamingContextBuilder устарел с весны 5.2 в пользу других решений, таких как Simple-JNDI .
4. Смоделируйте и протестируйте источник данных JNDI с помощью Simple-JNDI
Simple-JNDI позволяет нам привязывать объекты, определенные в файлах свойств, к издевательской среде JNDI . Он поставляется с большой поддержкой для получения объектов типа javax.sql.DataSource из JNDI за пределами контейнеров Java EE.
Итак, давайте посмотрим, как мы можем использовать его . Во-первых, нам нужно добавить зависимость Simple-JNDI в ваш pom.xml :
com.github.h-thurow simple-jndi 0.23.0
Последнюю версию библиотеки Simple-JNDI можно найти на Maven Central .
Далее мы настроим Simple-JNDI со всеми деталями, необходимыми для настройки контекста JNDI. Для этого нам нужно создать файл jndi.properties , который должен быть помещен в путь к классу :
java.naming.factory.initial=org.osjava.sj.SimpleContextFactory org.osjava.sj.jndi.shared=true org.osjava.sj.delimiter=. jndi.syntax.separator=/ org.osjava.sj.space=java:/comp/env org.osjava.sj.root=src/main/resources/jndi
java.naming.factory.initial указывает класс фабрики контекста, который будет использоваться для создания начального контекста.
org.osjava.sj.jndi.shared=true означает, что все InitialContext объекты будут совместно использовать одну и ту же память.
Как мы видим, мы использовали свойство org.osjava.sj.space для определения java:/comp/env в качестве отправной точки всех поисков JNDI.
Основная идея использования как org.osjava.sj.delimiter , так и jndi.syntax.separator properties заключается в том, чтобы избежать проблемы ANC .
org.osjava.sj.root свойство позволяет нам определить путь к тому, где хранятся файлы свойств . В нашем случае все файлы будут расположены в папке src/main/resources/jndi .
Итак, давайте определим объект javax.sql.DataSource внутри нашего файла data source.properties :
ds.type=javax.sql.DataSource ds.driver=org.h2.Driver ds.url=jdbc:jdbc:h2:mem:testdb ds.user=sa ds.password=password
Теперь давайте создадим объект InitialContext для нашего модульного теста:
@BeforeEach public void setup() throws Exception { this.initContext = new InitialContext(); }
Наконец, мы реализуем модульный тестовый случай для извлечения Источника данных объекта, уже определенного в файле datasource.properties :
@Test public void whenMockJndiDataSource_thenReturnJndiDataSource() throws Exception { String dsString = "org.h2.Driver::::jdbc:jdbc:h2:mem:testdb::::sa"; Context envContext = (Context) this.initContext.lookup("java:/comp/env"); DataSource ds = (DataSource) envContext.lookup("datasource/ds"); assertEquals(dsString, ds.toString()); }
5. Заключение
В этом уроке мы объяснили, как решить проблему тестирования JNDI вне контейнеров J2EE. Мы рассмотрели, как протестировать макет источника данных JNDI с помощью Spring Framework и библиотеки Simple-JNDI.
Как всегда, код доступен на GitHub .