2011-07-12 11 views
5

tengo una prueba JUnit @Transactional configurado y quiero persistir algunos datos de prueba a la base de datos y también comprobar si las asociaciones son correctos. Sin embargo, al probar las asociaciones, siempre evalúan nulo, aunque funciona en una prueba no transaccional.El uso de las asociaciones bidireccionales de objetos de dominio en @Transactional Junit Pruebas

I persisten dos objetos utilizando la anotación @Before:

@Before 
public void testData() { 
    TestObjectOne o = new TestObjectOne(); 
    o.setName("One"); 
    repo.saveEntity(o); //autowired 

    TestObjectTwo t = new TestObjectTwo(); 
    t.setOne(o); 
    t.setName("Two"); 
    repo.saveEntity(t); 
} 

Al acceder a esos dos objetos en una prueba, consigo el instancias correctas:

TestObjectOne o = repo.getOneByName("One"); 
    TestObjectOne t = repo.getTwoByName("Two"); 

Al comprobar sobre la asociación entre t y o, obtengo una referencia correcta porque definí explícitamente esa asociación:

Assert.assertNotNull(t.getOne()); 

Pero al comprobar en el revés, el objeto o no se actualiza correctamente:

Assert.assertNotNull(o.getTwos()); 

La asociación se define en el objeto de dominio como

En One:

@OneToMany(mappedBy = "one", fetch = FetchType.EAGER) 
    private List<Two> twos; 

en Two:

@ManyToOne(optional = false) 
    private One one; 

Cuando tengo la prueba no se ejecute como @Transactional, funciona muy bien, sin embargo.

edición ahorro de los organismos situados en la prueba en lugar del método @Before, no hace ninguna diferencia.

Respuesta

4

Usted necesita lavar y limpiar la sesión actual después de guardar y antes de cargar objetos de prueba para las aseveraciones.

al guardar el TestObjectOne o el caso de que se mantiene en sesión de Hibernate. Después de crear TestObjectTwo t y agregar referencia a o y guardarlo para que esta instancia ahora también se mantenga en la sesión de Hibernate. Después de llamar a Hibernate, obtiene las instancias que creó anteriormente sin actualizarlas para reflejar el estado real. Por lo tanto, debe vaciar y borrar la sesión antes de la carga, ya que la caché L1 de la sesión estará vacía y las entidades se cargarán correctamente.

public class MyTest { 

    @Before 
    public void setUp() { 

     TestObjectOne o = new TestObjectOne(); 
     o.setName("One"); 
     repo.saveEntity(o); //autowired 

     TestObjectTwo t = new TestObjectTwo(); 
     t.setOne(o); 
     t.setName("Two"); 
     repo.saveEntity(t); 

     /* push all changes to current transaction*/ 
     repo.getSessionFactory().getCurrentSession().flush(); 
     /* clean current session, so when loading objects they'll 
      be created from sratch and will contain above changes */ 
     repo.getSessionFactory().getCurrentSession().clear(); 
    } 

    @Test 
    public void test() { 
     TestObjectOne o = repo.getOneByName("One"); 
     TestObjectOne t = repo.getTwoByName("Two"); 

     Assert.assertNotNull(t.getOne()); 
     Assert.assertNotNull(o.getTwos()); 
    } 
} 
+0

despejando la sesión realmente hizo el trabajo. Gracias. sin embargo, siento que es un poco molesto ocuparse de la sesión durante la prueba mientras se maneja correctamente durante la primavera en un entorno de producción :(. ¿Hay alguna otra manera de probar esto? La prueba puede dar un falso positivo o un falso negativo porque olvidé enjuagar/borrar, lo que no tengo que hacer en el código de producción :( – chzbrgla

+1

Si desea una transacción única con una reversión al final, no, no creo que haya otra forma. Eso es cómo funciona Hibernate: la entidad se llena con datos de db solo una vez, cuando se carga en la sesión actual. Cuando descargue la sesión Hibernate realizará la actualización de sus datos en DB, pero no cambiará las entidades en la sesión actual. De hecho, funcionará de la misma manera en el código de producción si lo llamaras en una sola transacción. Funcionará correctamente solo si llamas a 'cargar' en otra transacción después de 'guardar'. – Roadrunner

+1

Para hacer las cosas un poco más fáciles I generalmente escribe una clase base para transacciones Pruebas ctional que @Autowires SessionFactory y tiene un único método 'flushAndClear()' que solo toma la sesión actual y llama a 'flush()' y 'clear()', pero aún necesita recordar llamarlo y recargar objetos antes de las aserciones . – Roadrunner

0

La anotación @Transactional provoca una reversión después de la prueba, lo que los resultados no se conservan en la base de datos.

Para las pruebas que requieren datos para ser persistido, se puede añadir la anotación @Rollback(false) además de la @Transactional uno.

+0

La extraña Hing es que en el caso de que algunos elementos se conservan (objetos) y otros elementos no son (relaciones). Tal vez tiene que ver con la tecnología de persistencia subyacente utilizada (JPA + Hibernate?). –

+0

Sé que @Transactional desencadena una reversión: eso es exactamente lo que quiero: p. Sin embargo, quiero que las asociaciones entre objetos se propaguen incluso dentro de la transacción.Y eso es lo que no está sucediendo en este momento. Estoy un poco atrapado aquí: p – chzbrgla

Cuestiones relacionadas