如何在不使用任何数据库的情况下测试Hibernate条件查询? [英] How to test Hibernate criteria queries without using any database?

查看:58
本文介绍了如何在不使用任何数据库的情况下测试Hibernate条件查询?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发带有许多复杂的Hibernate条件查询的Java应用程序.我想测试这些标准,以确保它们选择的是正确的对象,而仅仅是正确的对象.当然,一种解决方法是建立一个内存数据库(例如HSQL),并在每次测试中使用该条件往返于该数据库,然后断言查询结果符合我的期望.

I'm developing a Java application with lots of complex Hibernate criteria queries. I would like to test these criteria to make sure they are selecting the right, and only the right, objects. One approach to this, of course, is to set up an in-memory database (e.g. HSQL) and, in each test, make a round trip to that database using the criteria and then assert that the query results match my expectations.

但是我正在寻找一个更简单的解决方案,因为Hibernate标准只是关于Java对象的一种特殊的逻辑谓词.因此,从理论上讲,它们可以在根本不访问任何数据库的情况下进行测试.例如,假设存在一个名为Cat:

But I'm looking for a simpler solution, since Hibernate criteria are just a special kind of logical predicates about Java objects. Thus they could, in theory, be tested without accessing any database at all. For example, assuming that there is a entity called Cat:

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

我想做这样的事情来创建条件查询:

I would like to do something like this, to create criteria queries:

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

该标准可以在生产代码中使用,例如:

The criteria could be used in production code like this:

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

有没有可以进行这种测试的Java库?

Is there any Java library that makes this kind of test possible?

推荐答案

您可以使用Mockito之类的模拟框架来模拟所有相关的Hibernate类并定义这些模拟的预期行为.

You could use a mocking framework like Mockito to mock all relevant Hibernate classes and define expected behavior of these mocks.

听起来很像很多代码,但是由于Hibernate Criteria API是一个流畅的接口,所以Criteria的所有方法都返回一个新的实例Criteria.因此,定义所有测试通用的模拟行为很简单. 这是使用Mockito的示例

Sounds like a lot of code, but since the Hibernate Criteria API is a fluent interface, all methods of Criteria return a new instance Criteria. So defining the mock behavior which is common to all tests is simple. Here is an example using 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模拟的所有方法再次返回该模拟.

All methods of the Criteria mock return the mock again.

在具体测试中,您将使用ArgumentCaptorverify语句来调查模拟的Criteria发生了什么.

In a concrete test you would then use a ArgumentCaptor and verify statements to investigate what happened to the mocked 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());
}

我对这种unitest所见的问题是,他们对测试中的类强加了很多期望.如果您想到serviceUnderTest 作为黑匣子,您不知道它是如何通过名称检索cat对象的.它也可以使用LIKE准则,甚至使用'IN'代替=,此外,它还可以使用 Example标准.或者它可以执行本机SQL查询.

The problem I see with this kind of unitests is that they impose a lot of expectations about the class under test. If you think of serviceUnderTest as a blackbox, you can't know how it retrieves the cat object by name. It could also use a LIKE criterion or even 'IN' instead of =, further it could use the Example criterion. Or it could execute a native SQL query.

这篇关于如何在不使用任何数据库的情况下测试Hibernate条件查询?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆