Wednesday, September 14, 2011

Mock/Stub do EntityManager no Spring Roo

Problema

Ao tentar criar testes de unidade para o método persist de uma classe criada pelo Spring Roo, tentei utilizar um Stub para o EntityManager da seguinte forma:



public class ClasseATest {
    @Test
    public void aoPersistirDeveriaChamarClasseB() throws Exception {
        
        Mockery contexto = new Mockery();
        final ClasseB classeB = contexto.mock(ClasseB.class);
        
        final ClasseA classeA = 
            new ClasseA(getEntityManagerStub(), classeB);

        contexto.checking(new Expectations() {{
            one(classeB).fazerAlgo(classeA);

        }
    });
        classeA.persist();
        
        contexto.assertIsSatisfied();
    }

    private EntityManager getEntityManagerStub() {
        return new EntityManager() {
            ...
        }
    }
}
Código da ClasseA

public class ClasseA {
...

    public ClasseA(EntityManager entityManager, ClasseB classeB) {
        this.entityManager = entityManager;
        this.classeB = classeB;
    }



    @Transactional
    public void persist() {
        if (this.entityManager == null) this.entityManager = entityManager();
     
        this.entityManager.persist(this);
     
        classeB.fazerAlgo(this);
     
    }

...
 }


O teste funcionava quando era executado dentro de Eclipse, mas falhava quando era executado via maven, no momento da execução do mvn jetty:run-exploded.


Motivo

Provavelmente o spring roo está injetando o EntityManager logo após a chamada ao constructor.

Solução

Utilizar setter injection, como mostrado abaixo:


public class ClasseATest {
    @Test
    public void aoPersistirDeveriaChamarClasseB() throws Exception {
        
        Mockery contexto = new Mockery();
        final ClasseB classeB = contexto.mock(ClasseB.class);
        
        final ClasseA classeA =
            new ClasseA(classeB);
        classeA.setEntityManager(getEntityManagerStub());
        
        contexto.checking(new Expectations() {{
            one(classeB).fazerAlgo(classeA);

        }
    });
        classeA.persist();
        
        contexto.assertIsSatisfied();
    }

    private EntityManager getEntityManagerStub() {

        return new EntityManager() {
            ...
        }

    }
}


Código da ClasseA


public class ClasseA {
...

    public ClasseA(ClasseB classeB) {
        this.classeB = classeB;
    }


    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }




    @Transactional
    public void persist() {
        if (this.entityManager == null) this.entityManager = entityManager();
      
        this.entityManager.persist(this);
      
        classeB.fazerAlgo(this);
      
    }

...
 }


Provavelmente deve existir uma solução mais elegante, que permita a utilização da injeção da dependência no construtor. Quando tiver tempo vou pesquisar e bloggar a solução.






No comments:

Post a Comment