2012-02-09 17 views
10

Estoy desarrollando una aplicación Java con muchas consultas complejas de criterios de Hibernate. Me gustaría probar estos criterios para asegurarme de que están seleccionando los objetos correctos, y solo los correctos. Un enfoque para esto, por supuesto, es establecer una base de datos en memoria (por ejemplo, HSQL) y, en cada prueba, realizar un viaje de ida y vuelta a esa base de datos utilizando los criterios y luego afirmar que los resultados de la consulta coinciden con mis expectativas.Cómo probar las consultas de criterios de Hibernate sin usar ninguna base de datos?

Pero estoy buscando una solución más simple, ya que los criterios de Hibernate son solo un tipo especial de predicados lógicos sobre los objetos de Java. Por lo tanto, podrían, en teoría, probarse sin acceder a ninguna base de datos en absoluto. Por ejemplo, suponiendo que existe una entidad llamada Cat:

class Cat { 
    Cat(String name, Integer age){ 
     this.name = name; 
     this.age = age; 
    } 
    ... 
} 

me gustaría hacer algo como esto, para crear consultas de criterios:

InMemoryCriteria criteria = InMemoryCriteria.forClass(Cat.class) 
    .add(Restrictions.like("name", "Fritz%")) 
    .add(Restrictions.or(
     Restrictions.eq("age", new Integer(0)), 
     Restrictions.isNull("age"))) 

assertTrue(criteria.apply(new Cat("Foo", 0))) 
assertTrue(criteria.apply(new Cat("Fritz Lang", 12))) 
assertFalse(criteria.apply(new Cat("Foo", 12))) 

Los criterios podrían ser utilizados en el código de producción como esta :

criteria.getExecutableCriteria(session); //similar to DetachedCriteria 

¿Hay alguna biblioteca de Java que haga este tipo de prueba posible?

Respuesta

15

Puede utilizar un marco de burla como Mockito para simular todas las clases relevantes de Hibernate y definir el comportamiento esperado de estos simulacros.

Suena como un montón de código, pero como la API de criterios de Hibernate es una interfaz fluida, todos los métodos de Criteria devuelven una nueva instancia Criteria. Entonces, definir el comportamiento simulado que es común a todas las pruebas es simple. Aquí se muestra un ejemplo usando Mockito

@Mock 
private SessionFactory sessionFactory; 

@Mock 
Session session; 

@Mock 
Criteria criteria; 

CatDao serviceUnderTest; 

@Before 
public void before() 
{ 
    reset(sessionFactory, session, criteria); 
    when(sessionFactory.getCurrentSession()).thenReturn(session); 
    when(session.createCriteria(Cat.class)).thenReturn(criteria); 
    when(criteria.setFetchMode(anyString(), (FetchMode) anyObject())).thenReturn(criteria); 
    when(criteria.setFirstResult(anyInt())).thenReturn(criteria); 
    when(criteria.setMaxResults(anyInt())).thenReturn(criteria); 
    when(criteria.createAlias(anyString(), anyString())).thenReturn(criteria); 
    when(criteria.add((Criterion) anyObject())).thenReturn(criteria); 

    serviceUnderTest = new CatDao(sessionFactory); 
} 

Todos los métodos de la Criteria retorno mock la maqueta de nuevo.

En una prueba concreta, utilizaría las declaraciones ArgumentCaptor y verify para investigar qué sucedió con el Criteria burlado.

@Test 
public void testGetCatByName() 
{ 
    ArgumentCaptor<Criterion> captor = ArgumentCaptor.forClass(Criterion.class); 

    serviceUnderTest.getCatByName("Tom"); 

    // ensure a call to criteria.add and record the argument the method call had 
    verify(criteria).add(captor.capture()); 

    Criterion criterion = captor.getValue(); 

    Criterion expectation = Restrictions.eq("name", "Tom"); 

    // toString() because two instances seem never two be equal 
    assertEquals(expectation.toString(), criterion.toString()); 
} 

El problema que veo con este tipo de unidades es que imponen muchas expectativas sobre la clase bajo prueba. Si piensa en serviceUnderTest como blackbox, no puede saber cómo recupera el objeto cat por su nombre. También podría usar el criterio LIKE o incluso 'IN' en lugar de =, además podría usar el criterio Example. O podría ejecutar una consulta SQL nativa.

+4

¡Gracias por responder! Pero, como usted señala, este tipo de prueba verifica cómo se implementa la clase *, no cómo se supone que * se comporte *. Además, esta prueba se centra en otro servicio, que usa los criterios. Aunque esta es sin duda una funcionalidad importante, debería ser relativamente fácil de probar (desacoplando las clases con el uso correcto de las interfaces, la separación de responsabilidades, etc.). Aquí, estoy más interesado en probar el objeto Criteria en sí mismo. –

Cuestiones relacionadas