Junit Testing JNDI InitialContext outside the application server

前端 未结 3 1447
南笙
南笙 2020-12-31 01:47
Context context = new InitialContext();
dataSource = (DataSource) context.lookup(\"java:comp/env/jdbc/multiDS\");
connection = dataSource.getConnection();

相关标签:
3条回答
  • 2020-12-31 01:51

    The orthodox thing to do here would be to change you code so that the Context is injected into it (by a dependency injection framework, or manually). Then, you simply pass in a mock in your unit test.

    If you can't do this, and your code must create the IntialContext itself, then you will need to set up a fake JNDI implementation into which you can inject mocks. If you search the web for in-memory JNDI implementation or mock JNDI implementation, you will find various options, or you could write one yourself. Basically, you will need an implementation of InitialContextFactory which simply returns a suitable mock, which you then select by setting the java.naming.factory.initial system property.

    I had a crack at writing the necessary classes. Here you go:

    public class MockInitialContextFactory implements InitialContextFactory {
    
        private static final ThreadLocal<Context> currentContext = new ThreadLocal<Context>();
    
        @Override
        public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
            return currentContext.get();
        }
    
        public static void setCurrentContext(Context context) {
            currentContext.set(context);
        }
    
        public static void clearCurrentContext() {
            currentContext.remove();
        }
    
    }
    
    public class MockInitialContextRule implements TestRule {
    
        private final Context context;
    
        public MockInitialContextRule(Context context) {
            this.context = context;
        }
    
        @Override
        public Statement apply(final Statement base, Description description) {
            return new Statement() {
                @Override
                public void evaluate() throws Throwable {
                    System.setProperty(Context.INITIAL_CONTEXT_FACTORY, MockInitialContextFactory.class.getName());
                    MockInitialContextFactory.setCurrentContext(context);
                    try {
                        base.evaluate();
                    } finally {
                        System.clearProperty(Context.INITIAL_CONTEXT_FACTORY);
                        MockInitialContextFactory.clearCurrentContext();
                    }
                }
            };
        }
    }
    

    Use as follows:

    public class FooTest {
    
        private final Context context = mock(Context.class);
    
        @Rule
        public MockInitialContextRule mockInitialContextRule = new MockInitialContextRule(context);
    
        @Test
        public void testName() throws Exception {
            // set up stubbings on the context mock
            // invoke the code under test
        }
    }
    
    0 讨论(0)
  • 2020-12-31 01:54

    You can use the Spring implementation, it works like this:

    import org.springframework.mock.jndi.SimpleNamingContextBuilder;
    
    [...]
    
    SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
    builder.bind("jdbc/myDataSource", myDS);
    builder.activate();
    
    0 讨论(0)
  • 2020-12-31 02:12

    This is easily done with Simple-JNDI. Create a property file "jdbc/multiDS.properties" in your working directory to configure your datasource with these properties:

    type=javax.sql.DataSource
    driver=org.gjt.mm.mysql.Driver
    url=jdbc:mysql://localhost/testdb
    user=testuser
    password=testing
    

    Then instantiate the context with

    final Hashtable<String, String> env = new Hashtable<String, String>();
    env.put("org.osjava.sj.root", "working_dir");
    env.put("org.osjava.sj.jndi.shared", "true");
    env.put("java.naming.factory.initial", "org.osjava.sj.SimpleContextFactory");
    env.put("org.osjava.sj.delimiter", "/");
    env.put("org.osjava.sj.space", "java:comp/env")
    Context ctx = new InitialContext(env);
    

    After that you can call

    dataSource = (DataSource) context.lookup("java:comp/env/jdbc/multiDS");
    

    Find more info about Simple-JNDI here https://github.com/h-thurow/Simple-JNDI

    0 讨论(0)
提交回复
热议问题