如何在单元测试中模拟InitialContext构造函数 [英] How to mock InitialContext constructor in unit testing

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

问题描述

当我尝试模拟以下方法(方法是使用远程EJB调用业务逻辑)作为Junit测试,它给出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.......}

上述方法的单元测试

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

我相信虽然我们嘲笑<在测试方法中,强调>上下文,当调用 Whitebox.invokeMethod(ObjectOfsomeMethodClass,someMethod,id1,id2,map)方法时,不使用模拟对象,而不是th在原始方法(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).

推荐答案

手工制作

Handmade

As 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 的模拟。您可以根据需要自定义模拟,可能会在查找调用中返回更多模拟。

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

春天(由 / em>)

Spring (added by 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数据将从弹簧模拟器拉出。

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

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

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆