Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何使用默认构造函数伪造InitialContext_Java_Unit Testing_Initial Context - Fatal编程技术网

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

Java 如何使用默认构造函数伪造InitialContext,java,unit-testing,initial-context,Java,Unit Testing,Initial Context,全部, 我试图用一些古老的java代码(没有接口,没有抽象,等等)进行一些单元测试 这是一个使用ServletContext(我假设它是由Tomcat设置的)的servlet,它的数据库信息设置在web.xml/context.xml文件中。现在,我已经知道了如何创建一个伪ServletContext,但是代码已经完成了 InitialContext _ic = new InitialContext(); 到处都是(因此更换它是不可行的)。我需要找到一种方法,使默认的InitialConte

全部,

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

这是一个使用ServletContext(我假设它是由Tomcat设置的)的servlet,它的数据库信息设置在web.xml/context.xml文件中。现在,我已经知道了如何创建一个伪ServletContext,但是代码已经完成了

 InitialContext _ic = new InitialContext();
到处都是(因此更换它是不可行的)。我需要找到一种方法,使默认的InitialContext()能够在不引发异常的情况下执行
\u ic.lookup(val)

我假设context.xml是以某种方式加载的,但这一魔法是如何发挥作用的,我对此一无所知。有人有什么想法吗?

您可以使用它来模拟InitialContext的构造并控制其行为。构造函数模拟是有文档记录的


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

在以下操作之前尝试设置系统变量:

System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
        "org.apache.naming.java.javaURLContextFactory");
System.setProperty(Context.URL_PKG_PREFIXES,
        "org.apache.naming");
InitialContext ic = new InitialContext();

如果您正在使用JUnit,请遵循以下文档:

以下是我为单元测试设置重要上下文的解决方案。首先,我将以下测试依赖项添加到我的项目中:

<dependency>
  <groupId>org.apache.tomcat</groupId>
  <artifactId>catalina</artifactId>
  <version>6.0.33</version>
  <scope>test</scope>
</dependency>
最后,在我的每个测试类中,我添加了一个@BeforeClass方法,该方法调用setupInitialContext。

您考虑过吗

这很容易:

InitialContext ctx=mock(InitialContext.class)


顺便说一句,如果您选择使用mock,我建议您也阅读本文:

利用
InitialContext
使用SPI来处理其创建。您可以通过创建
javax.naming.spi.InitialContextFactory
的实现并通过系统属性
javax.naming.factory.initial
Context.initial\u Context\u 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();
        }
    }


} 
这是
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;
    }
}

在命令行输出
上,这是我的对象(易于在eclipse中设置)。我喜欢嘲笑和打短棍。如果你处理很多遗留代码,我也推荐Micheal Feather的。所有这些都是关于如何在程序中找到接缝,以便隔离特定的测试部分

今天,我遇到了同样的问题(我们无法使用PowerMock),并通过以下方式解决了这个问题:

  • 不要在构造函数中查找,这样当您在对象上调用@InitMock时,构造函数还不需要上下文

  • 创建一个在需要时检索服务bean的方法,如“getService().serviceMethod(param,param…)”:

  • 在测试中,设置它:

  • 穷人不使用外部库的独立实现:

    public class myTestClass {
        public static class TestContext extends InitialContext {
            public TestContext() throws NamingException {
                super(true /*prevents initialization*/);
            }
    
            static Object someExpectedValue = "the expected string or object instance";
    
            /*override the method(s) called by the legacy program on _ic, check the parameter and return the wanted value */
            public Object lookup(String name) throws NamingException {
                return name != null && name.equals("theValueOfVal") ? someExpectedValue : null;
            }
        }
    
        public static class TestInitialContextFactory implements InitialContextFactory {
            public Context getInitialContext(Hashtable<?, ?> arg0) throws NamingException {
                return new TestContext();
            }
        }
    
        public static void main(String[] args) throws SQLException {
            System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "the.package.myTestClass$TestInitialContextFactory");
            /*now call the legacy logic to be tested*/
            ...
    
    公共类myTestClass{
    公共静态类TestContext扩展了InitialContext{
    public TestContext()引发NamingException{
    super(true/*防止初始化*/);
    }
    静态对象someExpectedValue=“预期的字符串或对象实例”;
    /*重写_ic上的遗留程序调用的方法,检查参数并返回所需的值*/
    公共对象查找(字符串名称)引发NamingException{
    返回name!=null&&name.equals(“theValueOfVal”)?someExpectedValue:null;
    }
    }
    公共静态类TestInitialContextFactory实现InitialContextFactory{
    公共上下文getInitialContext(哈希表arg0)引发NamingException{
    返回新的TestContext();
    }
    }
    公共静态void main(字符串[]args)引发SQLException{
    
    System.setProperty(Context.INITIAL\u Context\u FACTORY,“the.package.myTestClass$TestInitialContextFactory”); /*现在调用要测试的遗留逻辑*/ ...

    您可以在
    查找
    方法的覆盖中使用
    开关
    ,返回传递给
    查找(val)的每个不同
    val
    值的预期值
    在整个遗留程序中。

    仅仅因为它经常出现并不意味着更换它肯定是不可行的。见鬼,即使只是更改为使用静态工厂方法也会允许更高的可测试性(尽管它显然不如某些替代方法好).1.PowerMock功能强大,但它确实引起了足够多的麻烦,因此更倾向于使用重构。我认为这是我正在尝试的最佳解决方案。谢谢!除非您没有其他选择,否则请避免使用PowerMock…大量文章解释了原因。这给出了
    java.lang.ClassNotFoundException:org.apache.naming.java.javaURLContextFactory
    您的项目中应该有tomcat环境。如果我使用JBoss,您必须添加tomcat jarsSo。我想我必须使用JBoss环境。谢谢!oracle博客的链接被断开,而不是“java.naming.initial.factory”,我认为正确的系统属性是“java.naming.factory.initial”。在lejava 6中的ast。感谢您的帖子!java.naming.factory.initial也适用于java 7.FWIW,在此之后,我为一个非常类似的问题写了一个非常类似的答案,我做了这个。Context.initial\u Context\u factory,所以您不想记住初始上下文工厂环境变量name的实际字符串值非常好
    -Djava.naming.initial.factory=initial.context.test.MyInitialContext
    
        /* Class ApplicationResourceProvider */
    
        /* We can mock this and set it up with InjectMocks */
        InitialContext ic;
    
        /* method hiding the lookup */
        protected ApplicationService getService() throws NamingException {
            if(ic == null)
                ic = new InitialContext();
            return (ApplicationService)ic.lookup("java:global/defaultApplicationLocal");
        }
    
    @Mock
    ApplicationService applicationServiceBean;
    
    @Mock
    InitialContext ic;
    
    @InjectMocks
    ApplicationResourceProvider arp;
    
    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        when(ic.lookup(anyString())).thenReturn(applicationServiceBean);
        ...
    }
    
    public class myTestClass {
        public static class TestContext extends InitialContext {
            public TestContext() throws NamingException {
                super(true /*prevents initialization*/);
            }
    
            static Object someExpectedValue = "the expected string or object instance";
    
            /*override the method(s) called by the legacy program on _ic, check the parameter and return the wanted value */
            public Object lookup(String name) throws NamingException {
                return name != null && name.equals("theValueOfVal") ? someExpectedValue : null;
            }
        }
    
        public static class TestInitialContextFactory implements InitialContextFactory {
            public Context getInitialContext(Hashtable<?, ?> arg0) throws NamingException {
                return new TestContext();
            }
        }
    
        public static void main(String[] args) throws SQLException {
            System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "the.package.myTestClass$TestInitialContextFactory");
            /*now call the legacy logic to be tested*/
            ...