如何使用默认构造函数伪造InitialContext

Aus*_*tin 14 java unit-testing initial-context

所有,

我试图在一些古老的java代码中进行一些单元测试(没有接口,没有抽象等)

这是一个使用ServletContext的servlet(我假设它是由Tomcat设置的),并且它在web.xml/context.xml文件中设置了数据库信息.现在,我已经弄清楚如何制作一个假的ServletContext,但代码有

 InitialContext _ic = new InitialContext();
Run Code Online (Sandbox Code Playgroud)

到处都是(所以更换它是不可行的).我需要找到一种方法来使默认的InitialContext()能够在_ic.lookup(val)不抛出异常的情况下完成.

我假设有一些方法可以加载context.xml,但是这个魔法是如何工作的,我正在画一个空白.有人有主意吗?

小智 35

利用InitialContext使用SPI处理其创建的事实.您可以通过创建一个实现javax.naming.spi.InitialContextFactory并通过系统属性javax.naming.factory.initial(Context.INTITIAL_CONTEXT_FACTORY)将其传递给您的测试来挂钩其生命周期.它比听起来更简单.

鉴于此类:

public class UseInitialContext {

    public UseInitialContext() {
        try {
            InitialContext ic = new InitialContext();
            Object myObject = ic.lookup("myObject");
            System.out.println(myObject);
        } catch (NamingException e) {
            e.printStackTrace();
        }
    }


} 
Run Code Online (Sandbox Code Playgroud)

这个impl InitialContextFactory:

public class MyInitialContextFactory implements InitialContextFactory {

    public Context getInitialContext(Hashtable<?, ?> arg0)
            throws NamingException {

        Context context = Mockito.mock(Context.class);
        Mockito.when(context.lookup("myObject")).thenReturn("This is my object!!");
        return context;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用.UseInitialContext在junit测试中创建实例

-Djava.naming.initial.factory=initial.context.test.MyInitialContext
Run Code Online (Sandbox Code Playgroud)

在命令行输出This is my object!!(易于在eclipse中设置).我喜欢Mockito嘲笑和抄袭.如果您处理大量遗留代码,我还建议Micheal Feather 有效地使用遗留代码.这一切都是关于如何在程序中找到接缝以隔离特定的测试件.

  • 'java.naming.factory.initial'也适用于java 7. (3认同)

Hir*_*o2k 6

这是我为单元测试设置Inintial Context的解决方案.首先,我将以下测试依赖项添加到我的项目中:

<dependency>
  <groupId>org.apache.tomcat</groupId>
  <artifactId>catalina</artifactId>
  <version>6.0.33</version>
  <scope>test</scope>
</dependency>
Run Code Online (Sandbox Code Playgroud)

然后我用以下代码创建了一个静态方法:

public static void setupInitialContext() throws Exception {
    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("jdbc");
    PGSimpleDataSource ds = new PGSimpleDataSource();
    ds.setDatabaseName("postgres");
    ds.setUser("postgres");
    ds.setPassword("admin");
    ic.bind("jdbc/something", ds);
}
Run Code Online (Sandbox Code Playgroud)

最后,在我的每个测试类中,我添加了一个调用setupInitialContext的@BeforeClass方法.


sam*_*wis 3

您可以使用PowerMock来模拟 InitialContext 的构造并控制其行为。构造函数模拟记录在此处

PowerMock 测试可能非常混乱和复杂,重构通常是更好的选择。