読者です 読者をやめる 読者になる 読者になる

単体テストを簡単に Unitils 〜データベーステスティング 1 〜


前回の単体テストを簡単に Unitils 〜アサーションユーティリティ〜 - etc9では、Unitils アサーションユーティリティについて見てきました。今回は Unitils のデータベーステストのサポートについて見ていきます。

Unitils のDBサポート環境構築

Spring + Hibernate の環境で、Unitils のDBサポートを見ていきます。まずは、環境構築から行います。前回までは Unitils 2.4 を使用していましたが、ここから3.0を使用していきます(特に理由はありません)。
前回までと同様 Maven にてプロジェクト作成します。以下のように指定し、その他はデフォルトを選択します。

> mvn archetype:generate

Define value for groupId: : etc9
Define value for artifactId: : unitils-db


続いて作成された pom.xml を以下のように編集します。Unitils 3.0 からはモジュール化が進んでいるため、unitils-core のようにモジュールを指定します。Hibernateアノテーションベースで使用するため、hibernate-annotations を指定します。また、データベースは hsqldb を使用するため、これも指定します。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>etc9</groupId>
  <artifactId>unitils-db</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>unitils-db</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
        <groupId>org.unitils</groupId>
        <artifactId>unitils-core</artifactId>
        <version>3.0</version>
    </dependency>
    <dependency>
        <groupId>org.unitils</groupId>
        <artifactId>unitils-orm</artifactId>
        <version>3.0</version>
    </dependency>
    <dependency>
        <groupId>org.unitils</groupId>
        <artifactId>unitils-dbunit</artifactId>
        <version>3.0</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-annotations</artifactId>
        <version>3.4.0.GA</version>
    </dependency>
    <dependency>
        <groupId>hsqldb</groupId>
        <artifactId>hsqldb</artifactId>
        <version>1.8.0.7</version>
    </dependency>
  </dependencies>
</project>


eclipse のプロジェクトに変換します。

> cd unitils-db
> mvn eclipse:eclipse


以下が依存として追加されます。大量です・

 o hsqldb:hsqldb:1.8.0.7
 o org.hibernate:hibernate-annotations:3.4.0.GA
 o org.hibernate:ejb3-persistence:1.0.2.GA
 o org.hibernate:hibernate-commons-annotations:3.1.0.GA
 o org.slf4j:slf4j-api:1.4.2
 o org.hibernate:hibernate-core:3.3.0.SP1
 o antlr:antlr:2.7.6
 o commons-collections:commons-collections:3.2
 o dom4j:dom4j:1.6.1
 o xml-apis:xml-apis:1.0.b2
 o javax.transaction:jta:1.1
 o org.unitils:unitils-core:3.0
 o junit:junit:4.4
 o commons-logging:commons-logging:1.1
 o commons-lang:commons-lang:2.3
 o ognl:ognl:2.6.9
 o org.unitils:unitils-dbunit:3.0
 o org.unitils:unitils-database:3.0
 o org.unitils:unitils-dbmaintainer:3.0
 o org.hibernate:hibernate:3.2.5.ga
 o net.sf.ehcache:ehcache:1.2.3
 o asm:asm-attrs:2.2.3
 o cglib:cglib:2.2
 o asm:asm:3.1
 o org.dbunit:dbunit:2.2.2
 o junit-addons:junit-addons:1.4
 o xerces:xercesImpl:2.6.2
 o xerces:xmlParserAPIs:2.6.2
 o poi:poi:2.5.1-final-20040804
 o org.slf4j:slf4j-nop:1.4.3
 o commons-dbcp:commons-dbcp:1.2.2
 o commons-pool:commons-pool:1.3
 o org.springframework:spring-jdbc:2.5.2
 o org.springframework:spring-beans:2.5.2
 o org.springframework:spring-core:2.5.2
 o org.springframework:spring-context:2.5.2
 o aopalliance:aopalliance:1.0
 o org.springframework:spring-tx:2.5.2
 o org.unitils:unitils-orm:3.0
 o org.unitils:unitils-spring:3.0
 o org.springframework:spring-test:2.5.2
 o org.springframework:spring-orm:2.5.2
 o javax.persistence:persistence-api:1.0

この辺の依存関係はバージョン違いなどで意味不明なエラーとなるので注意。
あとはeclipse にインポートです。

Spring + Hibernate によるテスト用アプリ作成

Unitils の動作確認用に、Spring + Hibernate にて簡単なテスト用のアプリケーションを作成します。まずは、Entity となる Item クラスを作成します。

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Item {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}


作成したItemクラスを検索するためのDaoのインターフェースと実装を作成します。

import java.util.List;

public interface ItemDao {
    Item get(Long id);
    Item save(Item item);
    List<Item> findByName(Item item);
}
import java.util.List;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateTemplate;

public class ItemDaoImpl implements ItemDao {
    private HibernateTemplate hibernateTemplate;

    @Autowired
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.hibernateTemplate = new HibernateTemplate(sessionFactory);
    }
    
    @Override
    public Item get(final Long id) {
        return (Item) this.hibernateTemplate.get(Item.class, id);
    }
    
    @Override
    public Item save(final Item item) {
        this.hibernateTemplate.save(item);
        return item;
    }
    
    @SuppressWarnings("unchecked")
    @Override
    public List<Item> findByName(Item item) {
        DetachedCriteria criteria = DetachedCriteria.forClass(Item.class);
        criteria.add(Example.create(item).enableLike());
        return hibernateTemplate.findByCriteria(criteria);
    }
}

findByName メソッドでは、Like 検索を行うため、enableLike() を指定しています。


作成した Dao を使い、Item を取得するサービスを作成します。

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;

public class ItemService {
    private ItemDao itemDao;

    @Autowired
    public void setItemDao(ItemDao itemDao) {
        this.itemDao = itemDao;
    }
    
    public void addNewItem(String name) {
        Item item = new Item();
        item.setName(name);
        itemDao.save(item);
    }
    public Item getItem(Long id) {
        return itemDao.get(id);
    }
    public List<Item> findByName(String name) {
        Item item = new Item();
        item.setName(name);
        return itemDao.findByName(item);
    }
}


次に Spring の設定ファイルを作成します。ソースフォルダの直下に applicationContext.xml を以下の内容で作成します。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">

  <context:annotation-config/>

  <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" destroy-method="close">
    <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
    <property name="url" value="jdbc:hsqldb:mem:etc9-unitils"/>
    <property name="username" value="sa"/>
    <property name="password" value=""/>
  </bean>

  <bean id="sessionFactory"
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="hibernateProperties">
      <value>
        hibernate.dialect = org.hibernate.dialect.HSQLDialect
        hibernate.show_sql = true
        hibernate.format_sql = true
        hibernate.hbm2ddl.auto = create
      </value>
    </property>
    <property name="annotatedClasses">
     <list><value>etc9.Item</value></list>
    </property>
  </bean>

  <bean id="itemService" class="etc9.ItemService">
  </bean>
  <bean id="itemDao" class="etc9.ItemDaoImpl">
  </bean>

</beans>

@Autowired を有効にするために を指定しています。また、DBはインメモリで動かすため、以下のように、mem を指定しています。

    <property name="url" value="jdbc:hsqldb:mem:etc9-unitils"/>


ここまで作成したアプリケーションを動作させてみます。Main クラスを以下のように作成し、アプリケーションを実行して Item の内容が表示されれば ここまでの準備は完了です。

import org.apache.commons.lang.builder.ToStringBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext(
                "applicationContext.xml");
        ItemService service = (ItemService) context.getBean("itemService");
        service.addNewItem("item1");
        service.addNewItem("item2");
        service.addNewItem("item3");

        System.out.println(ToStringBuilder.reflectionToString(service.getItem(1L)));
        
        for (Item i : service.findByName("item%")) {
            System.out.println(ToStringBuilder.reflectionToString(i));
        }
    }
}

Unitils の環境作成

ここからは、Unitils による DB アクセステストのための設定を行っていきます。Unitils にて DB を用いたテストを行うためには、Unitils の設定ファイルを用意する必要があり、以下の3種類があります。

  • unitils-defaults.properties:Unitils の Jar に含まれているデフォルト設定の定義
  • unitils.properties:プロジェクトレベルでの Unitils の設定
  • unitils-local.properties:パッケージなどのプロジェクトレベルより細かい Unitils の設定

ここでは、unitils.properties のみを扱います。unitils-local.properties を作成した場合は、unitils.properties の定義を上書く形で、より細かい単位での設定が可能です。


ソースフォルダの直下に以下の unitils.properties を作成します。通常、テスト用のソースフォルダの直下となるでしょう。

database.driverClassName=org.hsqldb.jdbcDriver
database.url=jdbc:hsqldb:mem:etc9-unitils
database.userName=sa
database.password=
database.schemaNames=PUBLIC

database.dialect=hsqldb

この定義ファイルで、Unitils 使用時のデータベースの接続先を指定します。schemaNames は省略できないため、PUBLIC のように、使用するデータベースに合わせたスキーマ名を指定する必要がある点に注意してください。


続いて、上記の Unitils の設定ファイルを Spring の定義ファイルから読み込むよう、applicationTestContext.xml のような名前でファイルを作成し以下の内容とします。この dataSource の設定により、unitils.properties に定義したの接続情報に基づきテストが行われることになります。なお、本ファイルもテスト用のソースフォルダの直下に配置してください。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
  <bean id="dataSource" class="org.unitils.database.UnitilsDataSourceFactoryBean" />
</beans>

テストケースの作成

準備は整ったので、テストケースの作成を行います。といきたい所ですが、長くなるので次回。単体テストを簡単に Unitils 〜データベーステスティング 2 〜 - etc9