MockEJB - JUnit Mockito - 无法在第二个单元测试中重新绑定模拟 EJB
Posted
技术标签:
【中文标题】MockEJB - JUnit Mockito - 无法在第二个单元测试中重新绑定模拟 EJB【英文标题】:MockEJB - JUnit Mockito - cannot rebind a mock EJB on second unit test 【发布时间】:2010-12-06 14:57:54 【问题描述】:您好,我有一个关于 MockEJB 的问题。我需要编写单元测试来测试调用 EJB 的代码。我使用 Mockito 为 EJB 编写一个 mock,并使用 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 示例非常相似。有人有想法吗?
谢谢
【问题讨论】:
您是否尝试过重置 JNDI 上下文? 您好,感谢您的光临!我仍在为此苦苦挣扎。重置 JNDI 上下文是什么意思?我试图在每次测试之前将其设置为 null,但它没有改变任何东西。你有别的想法吗? 【参考方案1】:是的,我找到了答案……就在昨天!实际上它与 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;
【讨论】:
【参考方案2】:在这些情况下,我发现在测试之外创建模拟并重用它更容易:
private static ServiceToMock serviceMock = mock(ServiceToMock.class);
@BeforeClass
public static void injectServiceSomewhere()
//...
@Before
public void resetServiceMock()
reset(serviceMock);
应该可以的。
【讨论】:
以上是关于MockEJB - JUnit Mockito - 无法在第二个单元测试中重新绑定模拟 EJB的主要内容,如果未能解决你的问题,请参考以下文章