繁体   English   中英

MockEJB-JUnit Mockito-无法在第二个单元测试中重新绑定模拟EJB

[英]MockEJB - JUnit Mockito - cannot rebind a mock EJB on second unit test

嗨,我有一个与MockEJB有关的问题。 我需要编写单元测试来测试正在调用EJB的代码。 我使用Mockito编写EJB的模拟,并使用MockEJB模拟JNDI上下文。

我的测试如下所示:

 @Test
 public void test1() throws Exception {
  // create a mock instance
  NetworkManager aMockManager = createMockNetworkManager();
  // deploy it in mock container and register it in JNDI
  registerMockNetworkManager(aMockManager);

  // encapsulates the JNDI lookup
  NetworkManager manager = NetworkManagerAccessor.getNetworkManager();
  // call a method
  manager.deleteObject(new TopicId(-1), null, this.userContext);
  // verify that the method was called on the mock
  verify(aMockManager).deleteObject(new TopicId(-1), null, this.userContext);
 }

 @Test
 public void test2() throws Exception {
  // create a mock instance
  NetworkManager aMockManager = createMockNetworkManager();
  // deploy it in mock container and register it in JNDI
  registerMockNetworkManager(aMockManager);

  // encapsulates the JNDI lookup
  NetworkManager manager = NetworkManagerAccessor.getNetworkManager();
  // call a method
  manager.deleteDataItem(new DataItemId(-1), null, null, null);

  // verify that the method was called on the mock
  verify(aMockManager).deleteDataItem(new DataItemId(-1), null, null, null);
 }

第一个测试运行良好,但是第二个测试系统性地失败了(mockito说未调用预期的方法)在调试时,我可以看到,第二次尝试将模拟EJB部署到JNDI时,它没有部署,并且第一个模拟对象仍然在那里。 因此,实际上第二个测试是从JNDI中提取第一个测试中创建的模拟。 还要注意,如果我单独运行第二个测试(通过注释第一个测试),则运行正常。

我的设置和清理方法如下所示:

 @Before
 public void setupMockJNDI() {
  try {

   // setup mockEJB
   MockContextFactory.setAsInitial();
   Context jndiContext = new InitialContext();

   // create the mock container
   mockContainer = new MockContainer( jndiContext );
  } catch (NamingException e) {
   e.printStackTrace();
  }

 }

 @After
 public void unregisterJNDI() {
  // reset mock context
  MockContextFactory.revertSetAsInitial();
 }

我真的不明白会发生什么,我的测试看起来与模拟EJB示例非常相似。 有人有主意吗?

谢谢

是的,我找到了答案……就在昨天! 实际上,它与MockEJB不相关,但是与我的代码有关,即执行JNDI查找缓存。 这个电话:

NetworkManager manager = NetworkManagerAccessor.getNetworkManager();

像这样对JNDI查找进行加密:

NetworkManagerHome home = (NetworkManagerHome)ServiceLocator.getInstance().getService(NetworkManagerHome.JNDI_NAME, NetworkManagerHome.class);

而且ServiceLocator 静态地缓存其JNDI查找以及JNDI上下文:

public Object getService(String jndiName, Class className) {        
    Object narrowedService = null;
    if (cache.containsKey(jndiName)) {
        narrowedService = cache.get(jndiName);
    } else {
        // see J2EE design patterns page 197
        synchronized(this) {
            try {
                Object service = ctx.lookup(jndiName);
                narrowedService = PortableRemoteObject.narrow(service, className);
            } catch (NamingException ne) {
                throw new ServiceLocatorException("Cannot find service : "+jndiName, ne);
            }
            cache.put(jndiName, narrowedService);
        }
    }
    return narrowedService;
}

因此,解决方案包括在每次测试之前重置此缓存:

Context jndiContext = new InitialContext();
ServiceLocator.getInstance().reset(jndiContext);

// in ServiceLocator :
public void reset(Context c) {
    this.cache = new Hashtable<String, Object>();
    this.ctx = c;
}

在这些情况下,我发现在测试之外创建模拟并重用它更容易:

private static ServiceToMock serviceMock = mock(ServiceToMock.class);

@BeforeClass
public static void injectServiceSomewhere(){
    //...
}
@Before
public void resetServiceMock() {
    reset(serviceMock);
}

那应该做。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM