0

こんにちは、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);
 }

最初のテストは正常に実行されますが、2 番目のテストは体系的に失敗します (mockito は、期待されるメソッドが呼び出されなかったと言っています)。デバッグ中に、2 回目にモック EJB を JNDI にデプロイしようとすると、デプロイされ、最初のモック オブジェクトはまだそこにあります。したがって、実際には、2 番目のテストは、最初のテストで作成されたモックの JNDI から取得されます。 また、(最初のテストにコメントを付けて) 2 番目のテストを単独で実行すると、正常に実行されることにも注意してください。

私のセットアップとクリーンメソッドは次のようになります:

 @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 の例と非常によく似ています。誰にもアイデアはありますか?

ありがとう

4

2 に答える 2

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;
}
于 2009-12-08T11:41:42.850 に答える
0

このような場合、テスト外でモックを作成して再利用する方が簡単だと思います。

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

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

それはそれを行う必要があります。

于 2010-06-14T17:53:29.550 に答える