EasyMockを使って標準出力に結果を出すプログラムをテストしてみる
2006-08-18の「標準出力に結果を出すプログラムをJUnit 4.1でテストする方法」と、それに対する反応を見て、ここまで来ると、ほとんどモックオブジェクトを使ったテストなのでは?と思いました。そこで、モックオブジェクトを使ったJunitのテストをサポートするライブラリ、EasyMockを使ってテストケースを書き直してみました。
事前準備
http://www.easymock.org/index.htmlのDownloadsからEasyMock 2.2とEasyMock 2.2 Class Extensionをダウンロード。
次に、http://cglib.sourceforge.net/のDopwnloadsから cglib-nodep-2.2_beta1.jarをダウンロード。これは、EasyMock 2.2 Class Extensionが利用するライブラリ。
テストコード
import junit.framework.TestCase; import java.io.PrintStream; import org.easymock.classextension.EasyMock; public class HelloTest extends TestCase { private PrintStream _saved; private PrintStream _outMock; public void setUp() { _saved = System.out; _outMock = EasyMock.createMock(PrintStream.class); // モックオブジェクト作成 System.setOut(_outMock); } public void tearDown() { System.setOut(_saved); } public void testHello() { // モックオブジェクトに振る舞いを記憶させる _outMock.println("Hello!"); _outMock.println("http://www.hyuki.com/"); // モックオブジェクトをreplay(記憶した振る舞いの再生)モードに切り替え EasyMock.replay(_outMock); // 実行 Hello.main(new String[0]); // モックオブジェクトが振る舞い通りに呼ばれたか確認 EasyMock.verify(_outMock); } }
replay()前のprintln()メソッド呼び出しの引数と、replay()後のprintln()メソッド呼び出しの引数が異なれば、AssertionErrorが投げられます。呼び出すメソッドが異なってもAssetionError。println()メソッド呼び出しの回数が少なければ、EasyMock.verify()がAsserionError。
ちなみに、普通は"import static org.easymock.EasyMock.*;"と書いて、クラス名を省略してEasyMockのstaticメソッド呼び出しを記述するようですが、EasyMockを使っている事を強調するため、あえてクラス名を明記してます。自分がJava 1.5の文法にまだ慣れてない、というのもあるけど。
実行例
eclipse 3.1.2で動作しました。
eclipseに付属のJUnit 3.8.1を直接使う場合は、下記のようなコマンドで。
C:\work>java -classpath ".;easymock.jar;easymockclassextension.jar;cglib-nodep-2.2_beta1.jar;C:\eclipse\plugins\org.junit_3.8.1\junit.jar" junit.textui.TestRunner HelloTest . Time: 0.391 OK (1 test)
これでテストコードはすっきりしますが、どうでしょう。依存するライブラリが多い点と、EasyMockの使い方を知らないと(慣れればそんな難しくないけど)テストコードが分かりにくい点が難点かな。
あ、あとt-wadaさんの日記で言及されている、テスト対象の実装との結合度がかなり高いという「モック/スタブベースのテストの短所」が思いっきり出てますね。HelloクラスでSystem.outの使い方(呼び出すメソッドとか)がちょっと変わっただけで(例え、標準出力の結果が同じでも)テストが失敗します。
単に標準出力へ出力する結果が合っていれば良い、というテストであれば、このテストコードは向かないかも。