Page List

Search on the blog

2013年6月20日木曜日

JUnitを使って単体テストをする(2)

 djUnitを使って遊んでみました。djUnitとは、JUnitの拡張版みたいなもので、
  • coverage report
  • virtual mock object
といった便利な機能を提供してくれるテストフレームワークです。

coverage reportはその名のとおり、テストのカバレッジを可視化してくれる機能です。テスト対象のソースで実行されていない行にマーカーを表示してくれます。
virtual mock objectは、メソッドの戻り値を自由に設定することでテスト用のモックを作成せずともテストができるという素晴らしい機能です。

具体的な使用方法は、以下のサンプルを見てください。

想定
Serviceクラスの単体テストをしたい。Serviceクラスは外部システムから情報を取得していて、取得した情報によって挙動が変わる。
単体テストなので、実際に外部システムには接続せずにテスト用のモックを使って動作確認をしたい。

まずテスト対象のServiceクラスです。doSomething()メソッドのテストを行うこととします。
package com.kenjih.main;

public class Service {
 public String doSomething() throws NumberFormatException {
  UserInfo userInfo = ExternalSystemLib.getUserInfo();
  
  if (userInfo == null)
   return "User Info is null.";  
  if (userInfo.getAge() < 0)
   throw new NumberFormatException();
  if (userInfo.getTel().startsWith("090"))
   return "Mobile phone number is registered.";
  
  return "His/Her name is " + userInfo.getName() + ".";
 }
}

以下がユーザー情報を格納するBeanです。
package com.kenjih.main;

public class UserInfo {
 private String name;
 private String tel;
 int age;
 
 public int getAge() {
  return age;
 }
 public void setAge(int age) {
  this.age = age;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getTel() {
  return tel;
 }
 public void setTel(String tel) {
  this.tel = tel;
 }
}

次に、外部システムと通信を行ってユーザー情報を取得する機能。
package com.kenjih.main;

public class ExternalSystemLib {
 public static UserInfo getUserInfo() {
  UserInfo userInfo = new UserInfo();
  
  // 実際は外部システムと通信をしてユーザー情報を取得するという想定。
  
  return userInfo;
 }
}
djUnitを使ったテスト
ExternalSystemLibMockのようなモックは作成せずともテストができます。仮想モックオブジェクトの機能を利用してテストを行います。
package test.kenjih.com;

import static org.junit.Assert.*;
import jp.co.dgic.testing.common.virtualmock.MockObjectManager;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.kenjih.main.ExternalSystemLib;
import com.kenjih.main.Service;
import com.kenjih.main.UserInfo;

public class TestService {

 Service service = new Service();
 
 @Before
 public void setUp() throws Exception {
  MockObjectManager.initialize();
 }

 @After
 public void tearDown() throws Exception {
 }

 @Test
 public void testDoSomething_1() {
  MockObjectManager.addReturnNull(ExternalSystemLib.class, "getUserInfo");
  
  assertEquals("User Info is null.", service.doSomething());
 }

 @Test(expected = NumberFormatException.class)
 public void testDoSomething_2() {
  UserInfo userInfo = new UserInfo();
  userInfo.setAge(-10);
  MockObjectManager.addReturnValue(ExternalSystemLib.class, "getUserInfo", userInfo);
  
  service.doSomething();
 }

 @Test
 public void testDoSomething_3() {
  UserInfo userInfo = new UserInfo();
  userInfo.setAge(20);
  userInfo.setName("Taro");
  userInfo.setTel("123456789");
  MockObjectManager.addReturnValue(ExternalSystemLib.class, "getUserInfo", userInfo);
  
  assertEquals("His/Her name is Taro.", service.doSomething());
 }

}

ポイントは、
  • MockObjectManager.addReturnNull(クラス, メソッド名); で指定したクラスのメソッドが必ずnullを返すように設定できる。
  • MockObjectManager.addReturnValue(クラス, メソッド名, 値); で指定したクラスのメソッドが必ず指定した値を返すように設定できる。
というところです。他にもいろいろ便利な機能があります。


実行結果
Eclipseでテスト実行した結果です。


テストで実行されていない行にマーカーが設定されます。

また、カバレッジの情報を外部ファイルにExportする機能もあります。



サマリーレポートも一緒にExportしてくれます。



いやー、便利ですね。

1 件のコメント:

  1. こんにちは。

    メソッド名をしていするのは、モックではなく、仮想モックオブジェクトだったんですね。

    返信削除