Junit测试应用服务器外部的JNDI InitialContext

tf7tbtn2  于 2022-11-11  发布在  其他
关注(0)|答案(4)|浏览(191)
Context context = new InitialContext();
dataSource = (DataSource) context.lookup("java:comp/env/jdbc/multiDS");
connection = dataSource.getConnection();

请帮我模拟一下上面的代码。
嗨,汤姆·安德森
我尝试了下面的代码

@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");            
            Context ic = new InitialContext();

            ic.createSubcontext("java:");
            ic.createSubcontext("java:comp");
            ic.createSubcontext("java:comp/env");
            ic.createSubcontext("java:comp/env/jdbc");
            ic.createSubcontext("java:comp/env/jdbc/multiDS");
            // Construct DataSource
            OracleConnectionPoolDataSource ds = new OracleConnectionPoolDataSource();
            ds.setURL("jdbc:oracle:thin:@g9u0696.houston.hp.com:1525:CRNAD");
            ds.setUser("uname");
            ds.setPassword("pwd");
        } catch (NamingException ex) {
            ex.printStackTrace();
        }
 }

但其施误为:

com.hp.corona.common.exception.CacheException: org.apache.naming.NamingContext cannot be cast to javax.sql.DataSource

请帮助我测试代码,我只想从JNDI数据源连接

ukqbszuj

ukqbszuj1#

这里要做的正统的事情是修改代码,以便将Context注入其中(通过依赖注入框架,或者手动)。然后,您只需在单元测试中传递一个mock。
如果你不能做到这一点,你的代码必须创建IntialContext本身,那么你将需要设置一个假的JNDI实现,你可以在其中注入模拟。如果你在网上搜索in-memory JNDI implementationmock JNDI implementation,你会发现各种各样的选项,或者你可以自己编写一个。基本上,你将需要一个InitialContextFactory的实现,它只返回一个合适的模拟。然后可以通过设置java.naming.factory.initial系统属性来选择它。
我在写必要的类时有一个裂缝。给你:

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

使用方法如下:

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
    }
}
dhxwm5r4

dhxwm5r42#

你可以使用Spring实现,它的工作方式如下:

import org.springframework.mock.jndi.SimpleNamingContextBuilder;

[...]

SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
builder.bind("jdbc/myDataSource", myDS);
builder.activate();
v1l68za4

v1l68za43#

使用Simple-JNDI可以轻松完成此操作。在工作目录中创建一个属性文件“jdbc/multiDS.properties“,以使用以下属性配置数据源:

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

然后使用以下命令示例化上下文

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

之后你可以打电话

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

有关Simple-JNDI的更多信息,请单击此处https://github.com/h-thurow/Simple-JNDI

polkgigr

polkgigr4#

我在一个要添加测试的遗留系统上使用建议的解决方案时遇到了问题,但我发现使用Mockito.mockConstruction是一种简单的方法:

public class FooTest {
  private final Context mockContext = mock(Context.class);

  @Test
  public void myTest()
      throws NamingException {

    try (final MockedConstruction<InitialContext> ignored = 
               mockConstruction(InitialContext.class,
               (mock, context) -> 
                    when(mock.lookup("java:comp/env"))
                    .thenReturn(mockContext)) {
    // Given
    when(mockContext.lookup("environmentEntry"))
        .thenReturn(desiredResult);
    ...
  }
}

相关问题