本文介绍了如何在单元测试中模拟 InitialContext 构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时删除!!

当我尝试为 Junit 测试模拟以下方法(方法使用远程 EJB 调用业务逻辑)时,它给出 javax.naming.NoInitialContextException

when I try to mock following method(Method is using remote EJB call for business logic) for the Junit test, it gives javax.naming.NoInitialContextException

private void someMethod(int id1, int id2, HashMap map){
    ......some code........

    Context ctx = new InitialContext();
    Object ref = ctx.lookup("com.java.ejbs.MyEJB");

    EJBHome ejbHome = (EJBHome)PortableRemoteObject.narrow(ref, EJBHome.class);
    EJBBean ejbBean = (EJBBean)PortableRemoteObject.narrow(ejbHome.create(), EJBBean.class);
    ejbBean.someMethod(id1,name);

    .......some code.......}

我对上述方法的单元测试

My unit test for above method

@Test
public void testsomeMethod() throws Exception {

    .......setting initial code...
    //Mock context and JNDI

    InitialContext cntxMock = PowerMock.createMock(InitialContext.class);
    PowerMock.expectNew(InitialContext.class).andReturn(cntxMock);
    expect(cntxMock.lookup("com.java.ejbs.MyEJB")).andReturn(refMock);

    ..........some code..........

    PowerMock.replayAll();
    Whitebox.invokeMethod(ObjectOfsomeMethodClass, "someMethod", id1, id2, map);


}

Whitebox.invokeMethod(ObjectOfsomeMethodClass, "someMethod", id1, id2, map) 方法调用时,它给出以下异常.

when the Whitebox.invokeMethod(ObjectOfsomeMethodClass, "someMethod", id1, id2, map) method invokes it gives following exception.

javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:645)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:325)
at javax.naming.InitialContext.lookup(InitialContext.java:392)

我相信,虽然我们在测试方法中模拟了Context,但在调用Whitebox.invokeMethod(ObjectOfsomeMethodClass, "someMethod", id1, id2, map) 时并没有使用模拟对象 方法,而不是尝试调用原始方法(someMethod)中的 Context ctx = new InitialContext(); 方法.

I believe, although we mock the Context in test method, it does not use the mock object when calling Whitebox.invokeMethod(ObjectOfsomeMethodClass, "someMethod", id1, id2, map) method, instead of that its trying to invoke the Context ctx = new InitialContext(); method in original method(someMethod).

推荐答案

手工制作

作为 InitialContext doc 说,您可以使用 java.naming.factory.initial 系统属性为 InitialContext 对象提供自己的工厂.当代码在应用服务器内部运行时,系统属性由服务器设置.在我们的测试中,我们提供了自己的 JNDI 实现.

As InitialContext doc says, you can provide your own factory for InitialContext objects, using java.naming.factory.initial system property. When the code runs inside application server, the system property is set by the server. In our tests, we provide our own implementation of JNDI.

这是我的 Mockito 唯一解决方案:我定义了一个自定义 InitialContextFactory 类,它返回 InitialContext 的模拟.您可以根据需要自定义模拟,可能会在 lookup 调用中返回更多模拟.

Here's my Mockito only solution: I defined a custom InitialContextFactory class, that returns a mock of InitialContext. You customize the mock as you wish, probably to return more mocks on lookup calls.

public class PlainTest {
  @Mock InitialContextFactory ctx;
  @InjectMocks Klasa1 klasa1;

  public static class MyContextFactory implements InitialContextFactory
  {
    @Override
    public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
      ConnectionFactory mockConnFact = mock(ConnectionFactory.class);
      InitialContext mockCtx = mock(InitialContext.class);
      when(mockCtx.lookup("jms1")).thenReturn(mockConnFact);
      return mockCtx;
    }
  }

  @Before
  public void setupClass() throws IOException
  {
    MockitoAnnotations.initMocks(this);
    System.setProperty("java.naming.factory.initial",
      this.getClass().getCanonicalName() + "$MyContextFactory");
  }

Spring(由 edit 添加)

如果您不介意利用 Spring Framework 进行测试,这里是他们的简单解决方案:SimpleNamingContextBuilder:

If you don't mind leveraging Spring Framework for testing purposes, here's their simple solution: SimpleNamingContextBuilder:

SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
DataSource ds = new DriverManagerDataSource(...);
builder.bind("java:comp/env/jdbc/myds", ds);
builder.activate();

放在@Before@BeforeClass 中就可以了.activate()后,jndi数据将从spring dummy中拉取.

It's ok to put it in @Before or @BeforeClass. After activate(), jndi data will be pulled from spring dummy.

这篇关于如何在单元测试中模拟 InitialContext 构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

1403页,肝出来的..

09-07 01:42