views:

679

answers:

4

Hi I have a question related to MockEJB. I need to write unit tests to test a code that is calling a EJB. I use Mockito to write a mock for the EJB, and MockEJB to simulate the JNDI context.

My tests look like this :

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

The first test runs fine, however the second test systematically fails (mockito says the expected method was not called) While debugging, I can see that the second time I attempt to deploy the mock EJB to the JNDI, it is not deployed, and the first mock object is still there. So in fact the second test is fecthing from the JNDI the mock created in the first test. Note also that if I run the second test alone (by commenting the first one), it runs fine.

My setup and clean method look like this :

 @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();
 }

I really don't understand what happens, my tests look very similar to the mock EJB examples. Does anyone have an idea ?

Thanks

A: 

Did you find the answer to this question? I have the exact same problem.

Mkn123
A: 

Yes I found the answer... just yesterday ! In fact it is not related to MockEJB, but to my code, that is doing JNDI lookup cache. This call :

NetworkManager manager = NetworkManagerAccessor.getNetworkManager();

Encpasulates the JNDI lookup like this :

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

And the ServiceLocator is statically caching its JNDI lookups, and also JNDI context :

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

So the solution consisted in reseting this cache before each test :

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

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

I am facing a similar problem, I am trying to write unit test cases in which I need to pass the ejbhandle, I need to mock the session bean and return the ejbhandle. Should I use MockEjb or mockito ?? Can you provide some sample code ??

Thanks JLion

Sorry I don't use EJB handles so I cannot provide sample code. MockEJB does not support EJB Handles.
Thomas
A: 

In these cases I find it easier to create the mock outside the tests and reuse it:

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

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

That should do it.

iwein