2010-08-11 10 views
15

Estoy tratando de ejecutar pruebas JUnit en clases de base de datos de "trabajador" que hacen una búsqueda jndi en un InitialContext para obtener un DataSource. Las clases de trabajadores generalmente se ejecutan en un servidor de aplicaciones de Glassfish v3 que tiene definidos los recursos jdbc adecuados.¿Cómo puedo vincular un DataSource a un InitialContext para la prueba de JUnit?

El código funciona bien cuando se implementa en el servidor de aplicaciones, pero no se ejecuta desde el entorno de prueba JUnit, porque obviamente no puede encontrar los recursos jndi. Así que traté de configurar un InitialContext en la clase de prueba que vincula un origen de datos al contexto apropiado, pero no funciona.

Aquí está el código que tengo en la prueba

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

Entonces la clase DataWorker tiene un método con el siguiente código, más o 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 
} 

Si cambio la
ic.createSubContext("java:/comp/env/jdbc");
ic.bind("java:/comp/env/jdbc/TestDS",testDS);
líneas a
ic.createSubContext("jdbc");
ic.bind("jdbc/TestDS",testDS);
La clase trabajadora es capaz de encontrar el origen de datos, pero no da un error que dice que "username al iniciar sesión en el servidor".

Si paso el DataSource que creo en el método JUnit directamente al trabajador, puede conectarse y ejecutar consultas.

Por lo tanto, me gustaría saber cómo enlazar un DataSource que puede ser buscado por la clase de trabajador sin estar en el contenedor web.

Respuesta

1

La última vez que intenté algo como esto hace unos años, finalmente me di por vencido y refactoré: en ese punto, NO podías crear un DataSource fuera de un contenedor. Tal vez puedas, ahora, tal vez alguien se burló de algo.

Aún así, eso huele ... No debe tener CUALQUIER código de "lógica de negocios" directamente dependiente de DataSources o búsquedas JNDI o tal. Eso es todo lo que se debe cablear fuera de su código.

¿Qué tan flexible es su diseño? Si su código bajo prueba depende directamente de un DataSource (o incluso obtiene su propia conexión), refactorícelo. Inyectar una conexión le permitirá probar todo lo que quiera con la antigua JDBC simple, incluso utilizando una implementación en memoria, y le ahorrará tener que apuntalar una infraestructura innecesaria (para la prueba, de todos modos) para hacerlo.

0

Encontré que ese ejemplo también es incorrecto. Esto funcionó para mí.

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

La diferencia se le nota es que el '/' después 'java:' en cada uno de los contextos que está mal y no debería estar allí.

Cuestiones relacionadas