我正在开发一个包含大量复杂Hibernate标准查询的Java应用程序。我想测试这些标准,以确保他们选择正确的,只有正确的对象。当然,一种方法是建立内存数据库(例如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库?
答案 0 :(得分:15)
您可以使用像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
作为一个黑盒子,你无法知道它如何通过名称检索猫对象。它也可以使用LIKE
标准甚至是'IN'而不是=
,它还可以使用。Example
{{1}}标准。或者它可以执行本机SQL查询。