Как протестировать запросы критериев Hibernate без использования базы данных? - PullRequest
10 голосов
/ 09 февраля 2012

Я занимаюсь разработкой Java-приложения со множеством сложных критериев запросов Hibernate.Я хотел бы проверить эти критерии, чтобы убедиться, что они выбирают правильные и только правильные объекты.Один из подходов к этому, конечно, состоит в том, чтобы создать базу данных в памяти (например, HSQL) и, в каждом тесте, совершить обратную поездку в эту базу данных, используя критерии, а затем утверждать, что результаты запроса соответствуют моим ожиданиям.

Но я ищу более простое решение, поскольку критерии Hibernate - это просто особый вид логических предикатов для объектов Java.Таким образом, теоретически они могут быть протестированы без доступа к какой-либо базе данных вообще.Например, если предположить, что существует объект с именем Cat:

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

Я хотел бы сделать что-то подобное для создания критериев запросов:

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)))

Критерии могут бытьиспользуется в производственном коде, подобном следующему:

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

Существует ли какая-либо библиотека Java, которая делает такой вид тестирования возможным?

1 Ответ

15 голосов
/ 23 февраля 2012

Вы можете использовать среду моделирования, такую ​​как Mockito, для моделирования всех соответствующих классов Hibernate и определения ожидаемого поведения этих образцов.

Звучит как много кода, но поскольку Hibernate Criteria API - это свободный интерфейс, всеметоды Criteria возвращают новый экземпляр Criteria.Так что определить фиктивное поведение, которое является общим для всех тестов, просто.Вот пример использования 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);
}

Все методы макета Criteria возвращают макет снова.

В конкретном тесте вы затем используете ArgumentCaptor и verifyзаявления о расследовании того, что случилось с поддельным Criteria.

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

Проблема, с которой я сталкиваюсь при такого рода объединениях, состоит в том, что они возлагают большие надежды на тестируемый класс.Если вы думаете о serviceUnderTest как о чёрном ящике, вы не можете знать, как он получает объект cat по имени.Он может также использовать критерий LIKE или даже 'IN' вместо =, кроме того, он может использовать критерий Example.Или он может выполнить собственный запрос SQL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...