簡體   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