2012-02-09 16 views
10

私は、多くの複雑なHibernate基準のクエリを持つJavaアプリケーションを開発しています。私は、これらの基準をテストして、彼らが正しいものを選択していることを確認したいと思います。これに対する1つのアプローチは、もちろん、メモリ内データベース(例えばHSQL)をセットアップし、各テストにおいて基準を使用してそのデータベースを往復させ、クエリ結果が私の予想と一致することをアサートすることである。データベースを使用せずにHibernate criteriaクエリをテストするには?

しかし、私は単純な解決策を探しています.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ライブラリはありますか?

答えて

15

Mockitoのようなモッキングフレームワークを使用して、関連するすべてのHibernateクラスをモックし、これらのモックの予想される動作を定義することができます。

は、多くのコードのような音が、Hibernateのクライテリア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モックリターンのすべてのメソッドを使用した例です。

具体的なテストでは、と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オブジェクトをどのように取得するのか分かりません。 の基準を使用することもでき、=の代わりに 'IN'を使用することもでき、さらに Exampleの基準を使用することもできます。または、ネイティブSQLクエリを実行できます。

+4

ありがとうございます。しかし、あなたが指摘しているように、この種のテストでは、クラスがどのように*実装されているかを検証します。さらに、このテストは別のサービスに集中しています。そのサービスは基準を使用します。これは確かに重要な機能ですが、インタフェースの適切な使用、責任の分離などでクラスをデカップリングすることで、テストするのは比較的簡単です。ここでは、Criteriaオブジェクト自体のテストにもっと興味があります。 –

関連する問題