Como posso ligar um DataSource a um InitialContext para testes JUnit?

Eu estou tentando executar testes JUnit em classs de “trabalhador” do database que fazem uma pesquisa de jndi em um InitialContext para obter um DataSource . As classs trabalhadoras são geralmente executadas em um servidor de aplicativos Glassfish v3 que possui os resources jdbc apropriados definidos.

O código é executado muito bem quando implementado no servidor de aplicativos, mas não é executado a partir do ambiente de teste da JUnit, porque obviamente não é possível encontrar os resources do jndi. Então eu tentei configurar um InitialContext na class de teste que liga uma fonte de dados ao contexto apropriado, mas não funciona.

Aqui está o código que tenho no teste

 @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); } } 

Em seguida, a class DataWorker tem um método com o seguinte código, mais ou menos

 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 } 

Se eu mudar o
ic.createSubContext("java:/comp/env/jdbc");
ic.bind("java:/comp/env/jdbc/TestDS",testDS) ;
linhas para
ic.createSubContext("jdbc");
ic.bind("jdbc/TestDS",testDS);
A class de trabalho é capaz de localizar o DataSource, mas falha ao fornecer um erro informando que “nome de usuário falhou ao efetuar login no servidor”.

Se eu passar o DataSource que eu crio no método JUnit diretamente para o worker, ele pode se conectar e executar consultas.

Portanto, gostaria de saber como vincular um DataSource que pode ser pesquisado pela class de trabalho sem estar no Contêiner da Web.

Quando eu tentei pela última vez algo assim há alguns anos, finalmente desisti e refatorei: nesse ponto, você NÃO poderia criar um DataSource fora de um contêiner. Talvez você possa, agora, talvez alguém tenha zombado de alguma coisa.

Ainda assim, isso cheira … Você não deveria ter QUALQUER “código de lógica de negócios” diretamente dependente de pesquisas de DataSources ou JNDI ou algo parecido. Isso é tudo para ser ligado fora do seu código.

Quão flexível é o seu design? Se seu código sob teste for diretamente dependente de um DataSource (ou até mesmo obter sua própria conexão), refatore-o. Injetar uma conexão permitirá que você teste tudo o que quiser com o antigo JDBC, mesmo usando uma implementação na memory, e evite que você precise criar muita infraestrutura desnecessária (para testar, pelo menos) para fazer isso.

Eu encontrei esse exemplo para estar errado também. Isso funcionou para mim.

 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); 

A diferença que você notará é que o ‘/’ após ‘java:’ em cada um dos contextos está errado e não deveria estar lá.

Intereting Posts