Injecting JNDI datasources for JUnit Tests outside of a container

来源:互联网 发布:魔术师生涯数据 编辑:程序博客网 时间:2024/06/01 09:05
I was working on some webservices that we're moving into libraries the other day, and needed to run a full set of tests using junit, but outside of a container. I didn't want to create and deploy an entire test harness, I just wanted to run the junit tests in the nb ide. But I couldn't get the test to inject the datasource resource so it was usable. I finally got it working, but I'll spare you all the pain I went through to get here. Here's how I did it in my test class:
    @BeforeClass
public static void setUpClass() throws Exception {
// rcarver - setup the jndi context and the datasource
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
OracleConnectionPoolDataSource ds = new OracleConnectionPoolDataSource();
ds.setURL("jdbc:oracle:thin:@host:port:db");
ds.setUser("MY_USER_NAME");
ds.setPassword("MY_USER_PASSWORD");

ic.bind("java:/comp/env/jdbc/nameofmyjdbcresource", ds);
} catch (NamingException ex) {
Logger.getLogger(MyDAOTest.class.getName()).log(Level.SEVERE, null, ex);
}

}

As you can see, in this case I used the OracleConnectionPoolDataSource,
you should use the datasource for your db connection. Don't forget to
link in the appropriate db jar (in my case it was ojdbc14.jar)
The code that is used to retrieve the datasource (which works for test
and production) looks like this:

Context initContext = new InitialContext();
Context webContext = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource) webContext.lookup("jdbc/nameofmyjdbcresource");

For SQLServer:
SQLServerConnectionPoolDataSource ds = new SQLServerConnectionPoolDataSource();
ds.setURL("jdbc:sqlserver://host:1433;databaseName=db");


Expose the JNDI name to the Web application
(
https://glassfish.dev.java.net/javaee5/ejb/compdependencies_xmlforum_nov15.pdf),
by Adding a 'resource-ref' element in web.xml like this:


  1. <resource-ref>
  2.    <res-ref-name>mail/initurfms</res-ref-name>
  3.    <res-type>javax.mail.Session</res-type>
  4.    <res-auth>Container</res-auth>
  5. </resource-ref>
Adding a 'reference-descriptor' element in weblogic.xml:
  1. <reference-descriptor>
  2.   <resource-description>
  3.     <res-ref-name>mail/initurfms</res-ref-name>
  4.     <jndi-name>mail/initurfms</jndi-name>
  5.   </resource-description>
  6. </reference-descriptor>
If you run your application in Weblogic, you don't need to create these two xml files, instead you can
configure the connectionpool, datasource directly in weblogic console. see JUnit关于数据库访问的单元测试 (2)--------------------------------
-------------------------------------------------------------------------------------------------------------

Another approach to unit test the datasource without the context:
using the class oracel.jdbc.xa.client.OracleXADataSourc

A factory for XAConnection objects. An object that implements the
XADataSource interface is typically registered with a JNDI service provider.
For optimization purposes, we implemented 2 versions of OracleXADataSource:
one for client, and one for server when used in Java Stored Procedures and
in EJB. The server-version is only available in 8.1.6 and post-8.1.6 backends.
This one is the implementation of OracleXADataSource for client-side usage
and works for both pre- and post-8.1.6 RMs.


public static DataSource createContractDataSource() throws SQLException {
OracleXADataSource dataSource;
dataSource = new OracleXADataSource();

dataSource.setUser(Configuration.getConfigurationProperty(Configuration.SKEL_DATABASE_USERNAME));

dataSource.setPassword(Configuration.getConfigurationProperty(Configuration.SKEL_DATABASE_PASSWORD));

dataSource.setURL(Configuration.getConfigurationProperty(Configuration.SKEL_DATABASE_URL));

Properties properties = new Properties();
properties.put("someproperty", "value");

dataSource.setConnectionProperties(properties);
return dataSource;
}

public class Configuration {

/** Configuration File Name. */
public static final String CONFIGURATION_FILE_NAME = "configuration.properties";

/** Skeleton Database Username. */
public static final String SKEL_DATABASE_USERNAME = "database.username";

/** Skeleton Database Password. */
public static final String SKEL_DATABASE_PASSWORD = "database.password";

/** Skeleton Database URL. */
public static final String SKEL_DATABASE_URL = "database.url";

private static Properties configuration = null;

private Configuration() {
//private so we can't instantiate the class
}


public static String getConfigurationProperty(String property) {
if (configuration == null) {
try {
loadConfiguration();
} catch (IOException e) {
//TODO error loading file, handle it better than this.
return null;
}
}

return configuration.getProperty(property);
}

private static void loadConfiguration() throws IOException {
configuration = new Properties();
InputStream input = ClassLoader.getSystemClassLoader().getResourceAsStream(
CONFIGURATION_FILE_NAME);

if (input == null) {
throw new FileNotFoundException(CONFIGURATION_FILE_NAME + " is not on the classpath");
}

configuration.load(input);
}

}