20

I am trying to set up some jUnit testing. Our database is connected by the server using JNDI. We have an xml describing the setup in root.xml. How do I set up jUnit to hook up to the database? I'd prefer to have it just read the the stuff off of root.xml, but I'm open to setting it up anyway that works.

Joe
  • 7,922
  • 18
  • 54
  • 83
  • You'll have to paste your root.xml file here, so potential answerers will know what kind of information they can be working with. Would you like your JUnit testers to run inside the server process, or as a standalone process? – Isaac Sep 22 '12 at 19:06
  • Are you using a dependency injection framework? – Kkkev Sep 23 '12 at 07:10
  • I don't have the root.xml now. It just has a couple database connections. – Joe Sep 23 '12 at 23:06
  • I am not using a dependency injection framework. – Joe Sep 23 '12 at 23:07
  • The root xml says this (basically): – Joe Sep 24 '12 at 14:31
  • See also http://stackoverflow.com/questions/5940895/how-to-test-a-mocked-jndi-datasource-with-spring – Vadzim Jul 05 '16 at 08:58

6 Answers6

15

I've found this Blog: https://blogs.oracle.com/randystuph/entry/injecting_jndi_datasources_for_junit

About H2 Datasource: http://www.h2database.com/javadoc/org/h2/jdbcx/JdbcConnectionPool.html

So for my Code:

package com.example.test;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.h2.jdbcx.JdbcConnectionPool;

import junit.framework.TestCase;

public class JunitDataSource extends TestCase {

    public void setUp() 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");

            JdbcConnectionPool ds = JdbcConnectionPool.create(
                    "jdbc:h2:file:src/main/resources/test.db;FILE_LOCK=NO;MVCC=TRUE;DB_CLOSE_ON_EXIT=TRUE", "sa", "sasasa");
            // 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:/mydatasourcename", ds);
        } catch (NamingException ex) {
            Logger.getLogger(JunitDataSource.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    public void testSimple() throws Exception {

        // Obtain our environment naming context
        Context initCtx = new InitialContext();

        // Look up our datasource
        DataSource ds = (DataSource) initCtx.lookup("java:/mydatasourcename");

        Connection conn = ds.getConnection();
        Statement stmt = conn.createStatement();

        ResultSet rset = stmt.executeQuery("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES");


        while (rset.next()) {
          System.out.println("<<<\t"+rset.getString("TABLE_NAME"));
        }


    }

}

Note: I had to add Tomcat Library and the jars inside the Tomcat's bin directory to get it working

FloFu
  • 609
  • 1
  • 5
  • 21
  • I'm having the same issue, what changes should I make to run it on `MySQL` ? – marknorkin Feb 07 '15 at 11:42
  • 1
    Just to help those that wonder where to find the jar containing org.apache.naming.java.javaURLContextFactory and assoc. -> Pick a recent TOMCAT server distribution, look for catalina.jar and tomcat-juli.jar, and add them to your classpath. You need too, of course, to add the database provider JDBC client jar to the classpath. – Bernard Hauzeur May 24 '17 at 16:47
10

I found that the best way to do it is to use something called Simple-Jndi.

I added this to the maven file:

    <dependency>
        <groupId>simple-jndi</groupId>
        <artifactId>simple-jndi</artifactId>
        <version>0.11.4.1</version>
        <scope>test</scope>
    </dependency>

You can download the the package here, the download contains an instruction manual. http://code.google.com/p/osjava/downloads/detail?name=simple-jndi-0.11.4.1.zip&can=2&q=

After adding to to your project you just have to add a couple of properties files, per the instructions.

However, after you add the dependency, I believe you can add your jndi resources programmatically instead of using properties files. You do something like this: (new InitialContext()).rebind("datasource",myDatasource);

Vadzim
  • 24,954
  • 11
  • 143
  • 151
Joe
  • 7,922
  • 18
  • 54
  • 83
  • Another guide on Simple-Jndi: http://fandry.blogspot.com.by/2011/03/junit-based-integration-testing-with.html – Vadzim Jul 05 '16 at 09:07
  • Neither of the guides above provide enough information to use simple-jndi. I've tried both, and the author's do not give enough detail for a first user to successfully use the library. (I've been trying for the past 2 days to make sense of their instructions). Are there any other resources which clearly explain how to use Simple-JNDI? – kiwicomb123 Mar 03 '17 at 05:42
  • 1
    The above-named Simple-JNDI project is not under active development anymore. So I forked it, did some bug fixes and implemented some new features. I also rewrote the introduction to make it more understandable. Give it a try please. See https://github.com/h-thurow/Simple-JNDI – Holger Thurow Jun 25 '17 at 07:04
4

I have used Simple-JNDI for this purpose for years now. It gives you an in-memory implementation of a JNDI Service and allows you to populate the JNDI environment with objects defined in property files. There is also support for loading datasources or connection pools configured in a file.

To get a connection pool you have to create a file like this:

type=javax.sql.DataSource
driver=com.sybase.jdbc3.jdbc.SybDriver
pool=myDataSource
url=jdbc:sybase:Tds:servername:5000
user=user
password=password 

In your application you can access the pool via

Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("path/to/your/connectionPool");

You can find more about it at https://github.com/h-thurow/Simple-JNDI.

TomcatJNDI helps with that situation too. It can process Tomcat’s configuration files and creates the same JNDI environment as Tomcat does, but without starting a server. So you can run classes with dependencies on Tomcat’s JNDI environment in e. g. JUnit tests.

TomcatJNDI tomcatJNDI = new TomcatJNDI();
tomcatJNDI.processContextXml(new File(“tomcat-root-dir/conf/context.xml”);
tomcatJNDI.start();

Then your classes can lookup the DataSource as when they would run in Tomcat.

More about TomcatJNDI can be found here: https://github.com/h-thurow/TomcatJNDI

Holger Thurow
  • 764
  • 4
  • 12
1

Would you like to create datasource programmatically on Application Server? Referene :

  1. Create Datasource JBoss 7 from program
  2. Create Datasource Weblogic from program

If you already created on Sever,

public class YourTestCase {
    private java.sql.Connection conn;

    @BeforeClass
    public static void init() {
        /* Weblogic */
        try {
            Context ctx = null;
            Hashtable ht = new Hashtable();
            ht.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
            ht.put(Context.PROVIDER_URL, "t3://<your-host>:<your:post>");
            ctx = new InitialContext(ht);
            javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup ("<your-datasource-jndi-name>");
            conn = ds.getConnection();
        } catch(Exception e) {

        }
        /* JBoss 5*/
        Context.INITIAL_CONTEXT_FACTORY ---> org.jnp.interfaces.NamingContextFactory
        Context.PROVIDER_URL ---->http://localhost:1099
    }
    @AfterClass
    public static void finished() {
    }


    @Test
    public void testMethod() {
        try {
            Statement stmt = conn.createStatement();
            stmt.execute("select * from someTable");
            ResultSet rs = stmt.getResultSet();  
                // do operation
            stmt.close();
            conn.close();
            } catch (Exception e) {
                // a failure occurred
            } finally {
                try {ctx.close();
                } catch (Exception e) {
                }
            }
        }
    }
}
Zaw Than oo
  • 9,651
  • 13
  • 83
  • 131
1

You can add Tomcat lib via maven dependency using below, to get it working.

<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>catalina</artifactId>
    <version>6.0.18</version>
    <scope>test</scope>
</dependency>
Ravindra S
  • 49
  • 6
0

I think you should try to mock out the database. Use appropriate framework, for example Mockito, it creates mocks and have DI abilities.

alexsmail
  • 5,661
  • 7
  • 37
  • 57
  • Will Mockito make JNDI data sources for me? I can't change around how the existing code works, because me boss would be very unhappy with that. – Joe Sep 23 '12 at 23:08