Как я могу привязать DataSource к InitialContext для тестирования JUnit?
Я пытаюсь запустить тесты JUnit на основе "рабочих" классов базы данных, которые ищут jndi на InitialContext
, чтобы получить DataSource
. Рабочие классы обычно запускаются на сервере приложений Glassfish v3, который имеет соответствующие ресурсы jdbc.
Код работает очень хорошо при развертывании на сервере приложений, но не запускается из среды тестирования JUnit, потому что, очевидно, он не может найти ресурсы jndi. Поэтому я попытался настроить InitialContext в тестовом классе, который привязывает источник данных к соответствующему контексту, но он не работает.
Вот код, который у меня есть в тесте
@BeforeClass
public static void setUpClass() throws Exception {
try {
// Create initial context
System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"org.apache.naming.java.javaURLContextFactory");
System.setProperty(Context.URL_PKG_PREFIXES,
"org.apache.naming");
InitialContext ic = new InitialContext();
ic.createSubcontext("java:");
ic.createSubcontext("java:/comp");
ic.createSubcontext("java:/comp/env");
ic.createSubcontext("java:/comp/env/jdbc");
// Construct DataSource
SQLServerConnectionPoolDataSource testDS = new SQLServerConnectionPoolDataSource();
testDS.setServerName("sqlserveraddress");
testDS.setPortNumber(1433);
testDS.setDatabaseName("dbname");
testDS.setUser("username");
testDS.setPassword("password");
ic.bind("java:/comp/env/jdbc/TestDS", testDS);
DataWorker dw = DataWorker.getInstance();
} catch (NamingException ex) {
Logger.getLogger(TitleTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
Затем класс DataWorker
имеет метод со следующим кодом, более или менее
InitialContext ic = null;
DataSource ds = null;
Connection c = null;
PreparedStatement ps = null;
ResultSet rs = null;
String sql = "SELECT column FROM table";
try{
ic = new InitialContext();
ds = (DataSource) ic.lookup("jdbc/TestDS");
c = ds.getConnection();
ps = c.prepareStatement(sql);
// Setup the Prepared Statement
rs = ps.executeQuery();
if(rs.next){
//Process Results
}
}catch(NamingException e){
throw new RuntimeException(e);
}finally{
//Close the ResultSet, PreparedStatement, Connection, InitialContext
}
Если я изменю
ic.createSubContext("java:/comp/env/jdbc");
ic.bind("java:/comp/env/jdbc/TestDS",testDS)
;
линии в
ic.createSubContext("jdbc");
ic.bind("jdbc/TestDS",testDS);
Рабочий класс может найти DataSource, но не дает ошибки, говоря, что "username не удалось войти в систему на сервере".
Если я передам DataSource, который я создаю в методе JUnit, непосредственно в рабочий, он может подключаться и запускать запросы.
Итак, я хотел бы знать, как связать DataSource, который может быть просмотрен рабочим классом, не находясь в веб-контейнере.
Ответы
Ответ 1
Когда я последний раз пробовал что-то вроде этого несколько лет назад, я, наконец, сдался и реорганизовался: в этот момент вы не могли бы создать DataSource за пределами контейнера. Может быть, теперь, может быть, кто-то издевался над чем-то.
Тем не менее, это пахнет... У вас не должно быть НИКАКОГО кода "бизнес-логики", напрямую зависящего от данных DataSources или JNDI или таких. Чтобы все сантехника была подключена за пределами вашего кода.
Насколько гибка ваша конструкция? Если ваш тестируемый код напрямую зависит от источника данных (или даже получает его собственное соединение), реорганизовать его. Injecting the Connection позволит вам протестировать все, что вам нравится, с помощью простого старого JDBC, даже используя встроенную реализацию, и избавит вас от необходимости поддерживать много ненужной (для тестирования, в любом случае) инфраструктуры для этого.
Ответ 2
Я нашел этот пример неверным. Это сработало для меня.
ic.createSubcontext("java:comp");
ic.createSubcontext("java:comp/env");
ic.createSubcontext("java:comp/env/jdbc");
final PGSimpleDataSource ds = new PGSimpleDataSource();
ds.setUrl("jdbc:postgresql://localhost:5432/mydb");
ds.setUser("postgres");
ds.setPassword("pg");
ic.bind("java:comp/env/jdbc/mydb", ds);
Разница, которую вы заметите, заключается в том, что "/" после "java:" в каждом из контекстов неверен и не должен быть там.