2009-10-14 13 views
0

Salut J'ai une question liée à MockEJB. J'ai besoin d'écrire des tests unitaires pour tester un code qui appelle un EJB. J'utilise Mockito pour écrire un simulacre pour l'EJB, et MockEJB pour simuler le contexte JNDI.MockEJB - JUnit Mockito - ne peut pas relier un simulacre d'EJB au deuxième test unitaire

Mes tests ressemblent à ceci:

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

Le premier test fonctionne très bien, mais le second test échoue systématiquement (Mockito dit la méthode prévue n'a pas été appelé) Bien que le débogage, je peux voir que la deuxième fois que je tenter de déployer l'EJB simulé sur le JNDI, il est pas déployé, et le premier objet fantôme est toujours là. Donc en fait le deuxième test est issu du JNDI le faux créé lors du premier test. Notez également que si je lance le second test seul (en commentant le premier), il fonctionne bien.

Ma configuration et la méthode propre ressembler à ceci:

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

Je ne comprends vraiment pas ce qui se passe, mes tests sont très similaires aux exemples EJB maquettes. Est-ce que quelqu'un a une idée ?

Merci

+0

Avez-vous essayé de réinitialiser le contexte JNDI? –

+0

Salut Merci pour votre visite! Je me bats toujours sur ça. Que voulez-vous dire par la réinitialisation du contexte JNDI? J'ai essayé de le mettre à zéro avant chaque test, mais cela n'a rien changé. Aviez-vous quelque chose d'autre en tête? – ThomasFrancart

Répondre

1

Oui j'ai trouvé la réponse ... juste hier! En fait, il n'est pas lié à MockEJB, mais à mon code, c'est le cache de recherche JNDI. Cet appel:

NetworkManager manager = NetworkManagerAccessor.getNetworkManager(); 

Encpasulates la recherche JNDI comme ceci:

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

Et le ServiceLocator est statiquement cache ses recherches JNDI, et le contexte aussi 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; 
} 

Ainsi, le La solution consistait à réinitialiser ce cache avant chaque 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; 
} 
0

Dans ces cas, je trouve plus facile de créer la maquette en dehors des essais et de la réutiliser:

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

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

Cela devrait le faire.