近年、JUnitとHudsonを利用した継続的インテグレーション(CI)によるテストの自動化や、テスト駆動開発(TDD)の普及などにより、ユニットテスト(単体テスト)のテストコードの作成が重要視されています。
今回紹介する「Quick JUnit」プラグインは、JUnitによるテストコードの作成と実装を支援するEclipseプラグインです。Quick JUnitプラグインは石井勝さんにより開発されていましたが、石井さんが不慮の事故により死去後、Quick JUnitプラグインプロジェクトにより開発が継続されています。優れたオープンソースプロジェクトの模範のようなプロジェクトです。
訂正のお知らせ
故人のお名前について間違いがあり、修正させていただきました。
内容について正確を期せずに混乱を招いた点、故人およびご家族、関係者、読者の皆様におわび申し上げます(2010年8月3日)。
Quick JUnitは、次のような3つの大きな特徴を持っています。
テストコードの切り替え機能により、開発者は、たくさんのコードの中から現在エディタで開いているテストコードを探す手間が省けます。
また、エディタ上で編集しているテストコードから、テスト元のコードを開くことも一瞬でできます。この機能により、現在実装しているクラスのテストクラスを簡単に表示できます。
従来のEclipseではテストクラス単位でしかテストを実行できませんでしたが、Quick JUnitを導入すれば、JUnitのテストケースのメソッド単位でテストを実行できます。この機能により、メソッドごとに実装・テストを迅速に行えます。
「EasyMock」などより簡潔なモックができるオープンソースの「Mockito」がJavaのモックフレームワークとして人気上昇中ですが、Quick JUnitは、Mockitoによるテスト作成を支援する機能があります。Mockitoを利用することにより、ミドルウェアや外部システムを利用するクラスのテストケースの作成を効率的に行えます。
Mockitoのより詳細な情報については、下記ページをご覧ください。また、EasyMockとの違いに興味がある方は、Mockitoプロジェクト上の記事「Mockito VS EasyMock」もご覧ください。
これらの機能により、実装、テストコード作成、メソッド単位のテストの実行をスムーズに行えます。
Eclipseのメニューの[新規ソフトウェアインストール]を利用して、下記のアップデートサイトを入力してプラグインをインストールしてください。
またEclipse 3.6からは、「Eclipse Marketplace」からQuick JUnitプラグインを検索してインストールすることもできるようになっています(図1)。「Eclipse Marketplace」は、Eclipseのメニューの[Help]から[Eclipse Marketplace...]を選択すると、利用できます。
テストケースの切り替えとメソッドのテストの実行のイメージは図2の通りです。実装コードをエディタに表示した状態で[Ctrl]+[9]キーを押すだけで、エディタをテストコードに切り替えられます。
また、テストコードをエディタに表示しているときは、実装コードに切り替えます。実装コードとテストコードのソースフォルダが別の場合でも簡単に切り替えられるので、非常に便利です。
通常、実装コードとテストコードは別のフォルダに置くため、切り替えるのに時間がかかってしまいますが、Quick JUnitを利用すると、まさに一瞬で実装コードとテストコードを切り替えれます。
テストコードが存在しない場合、[Ctrl]+[9]キーを押すとテストコードのひな型も生成できます。メソッド上で[Ctrl]+[0]キーを押すと、特定のメソッドのみユニットテストを実行できます。
なお、Quick JUnitは、例えばXXX.javaというソースコードに対してXXXTest.javaとクラス名の後にTestがついたクラスをテストコードとして扱います。
システム間の連携やデータベースなどのミドルウェアを利用したソフトウェアのテストでは、ユニットテストのために関連システムのセットアップやミドルウェアを設定すると、テスト1つ1つに非常に時間がかかってしまいます。そのような場合、DI(依存性の注入)を利用した開発では、従来、インターフェイスを定義して実装クラスとテスト用のモッククラスを切り替えてテストを行うようにいわれてきました。
しかし、実装クラスごとにインターフェイスとモッククラスを用意する必要があったり、テストごとにDIコンテナの設定ファイルを切り替える必要があったり、非常に煩雑になります。
Quick JUnitでは、Mockitoを利用したモック生成をサポートしています。Mockitoを利用すれば、データベースなどに依存した実装クラスのオブジェクトにインターフェイスの作成や設定ファイルの切り替えをすることなしにテストを行うことができます。
テストメソッドを作成したい場所にカーソルを移動させ、[q](アルファベットのキュー)キーを入力した後、[Ctrl]+[スペース]キーでEclipseのコードアシスト機能を利用すると、[Quick JUnit Mockito Integration]が表示されます(図3)。
この[Quick JUnit Mockito Integration]を選択すると、テストメソッドのひな型が生成されるとともに、JUnitやMockitoを利用するためのimport文が追加されます(図4)。
また、プロジェクトにMockitoのjarへのクラスパスが通っていない場合、Mockitoのインポート文の警告をクリックし、[Fix project setup](プロジェクトのセットアップを修正)を選択します(図5)。
すると[Mockitoをライブラリへ追加する]という修正候補が表示される(図6)ので、[OK]と押すとQuick JUnitプラグインが内部で持っているMockitoのjarにクラスパスを自動的に通してくれます。
さて、ここまででQuick JUnitを使うと、Mockitoを簡単に使えることは分かりましたが、実際にMockitoを利用したテストを作成してみましょう。次のように、CartService.javaの中にカートの合計金額を計算するロジックがあるとします。
package xxx.yyy.zzz; : 【省略】 : public class CartService { @Inject CartDao dao; @Inject User user; public void setCartDao(CartDao dao){ this.dao = dao; } @Inject public void setUser(User user){ this.user = user; } // 現在のユーザーのカート内の商品の合計を計算 public int calcTotal(){ List<CartItem> itemList = dao.findCartItemsByUserID(user.getID()); int total = 0; for(CartItem item:itemList){ total += item.getPrice(); } return total; } }
上記のメソッドは、DAO(Data Access Object)を利用して商品一覧を取得していますが、そのDAOが次のようなコードだとします。
package org.ultimania.sample; import java.util.List; import javax.persistence.*; public class CartDao { @PersistenceContext EntityManager entityManager; : 【省略】 : @SuppressWarnings("unchecked") public List<CartItem> findCartItemsByUserID(String name) { String queryStr = "select b from " + CartItem.class.getName() + " b where b.name=:name"; Query query = entityManager.createQuery(queryStr); query.setParameter("name", name); return (List<CartItem>) query.getResultList(); } : 【省略】 : }
findCartItemByUserIDメソッドは、内部でJPA(Java Persistence API)を利用しており、CartServiceのテストを作成しようとすると、データベースを作成して、データベース内にデータを設定して、と煩雑になってしまいます。
Mockitoを利用すると、次のような感じでfindItemsByUserID()の実行結果を疑似的に設定でき、純粋にCartServiceクラスのテストだけができます。
@Test public void testCalcTotal() { // テスト用のデータ作成 User user = new User("okamototk"); List<CartItem> itemList = new ArrayList<CartItem>(); itemList.add(new CartItem("不愉快痛恨開発環境〜こうしてダメな社内開発環境は作られる〜",2480)); itemList.add(new CartItem("トラブルハック大全〜火消の極意〜",2980)); itemList.add(new CartItem("ウォータフォールは滅びぬ何度でも蘇るさ",1980)); // モックのDAOオブジェクト作成 CartDao dao = mock(CartDao.class); // dao.findCartItemsByUserID("okamototk")を実行したときにitemListを // 返却するようにdaoを設定 when(dao.findCartItemsByUserID("okamototk")).thenReturn(itemList); // カートをインスタンス化し、DAOとユーザーオブジェクトを設定 CartService cart = new CartService(); cart.setCartDao(dao); cart.setUser(user); // テスト対象のメソッドの実行 int total = cart.calcTotal(); assertEquals(total,7440); }
データベースを利用したテストでは、テストごとにデータベースを初期化したり、テスト用データの投入を設定するなど煩雑な作業が必要であったり、データベースのセットアップコードをテストコードとして記述する必要がありますが、Mockitoを利用すれば、ほかのクラスの戻り値を簡単に設定できます。
これを応用すれば、Mockitoシステム間の接続が必要な場合や、ミドルウェアが必要なテストで接続対象のシステムやミドルウェアがなくても、ユニットテストを実施できます。
Quick JUnitの提供する機能は非常にシンプルですが、まさにかゆいところに手が届くツールとなっています。一度、Quick JUnitを使い始めると便利で病みつきになってしまいます。ぜひQuick JUnitを導入して、テストを効率化してみてください。
Copyright © ITmedia, Inc. All Rights Reserved.