標準出力に結果を出すプログラムの結果をファイルと比較してテストしてみる
EasyMockを使って標準出力に結果を出すプログラムをテストしてみるの続き。
この前のEasyMockを使ったテストは、「モック/スタブベースのテスト」の極端な例とも言えそう。System.outの使い方が変わるだけでテストが失敗するので、標準出力の結果を確認したいテストには向かないと思われる。じゃあ、「モック/スタブベースのテスト」の反対はどんなものなのだろう。やはり結城さんが最初に書いた、「ByteArrayOutputStreamにリダイレクト」させて標準出力の結果を比較するのが「モック/スタブベースのテスト」の反対なのだろう。これを何と呼ぶのか知らないのだけれど。
では、これをさらに極端にするとどうなるか。そう考えて、標準出力の結果をテストコード中の文字列と比較するのではなく、ファイルの内容と比較するのはどうだろうかと思いついた。
事前準備
Helloクラスが標準に出力する内容を、下記のように記述したテキストファイル"result.txt"を作成する。
Hello! http://www.hyuki.com/
テストコード
テストコードはこんな感じ。結城さんが書いたTestHello.javaと比べて、testHello()が少し違って、loadFile()が追加されてます。
import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.PrintStream; import java.io.Reader; import junit.framework.TestCase; public class TestHello extends TestCase { private ByteArrayOutputStream _baos; private PrintStream _out; public void setUp() { _baos = new ByteArrayOutputStream(); _out = System.out; System.setOut( new PrintStream( new BufferedOutputStream(_baos) ) ); } public void tearDown() { System.setOut(_out); } public void testHello() throws IOException { Hello.main(new String[0]); System.out.flush(); String expected = loadFile("result.txt"); String actual = _baos.toString(); assertEquals(expected, actual); } private String loadFile(String fileName) throws IOException { StringBuffer buf = new StringBuffer(); Reader reader = new BufferedReader(new FileReader(fileName)); int ch; while((ch = reader.read()) != -1) { buf.append((char)ch); } return buf.toString(); } }
これだと、標準出力に出力すべき結果をそのままテキストファイル"result.txt"に書けば良いので、出力結果を変える必要があっても、テストコードは変えずに"result.txt"のみ変えれば良い。前のと比べて汎用的なテストコードになってます。
あと、改行コードの違いの吸収は"result.txt"の改行コードを変える事で対応できるっぽい。どの環境でもうまくいくのか確認してないけれど、WindowsのJava実行環境で"result.txt"の改行コードをUnixのものにしたら、テストが失敗したのは確認できた。改行コードが異なる環境ごとに"result.txt"を用意しないといけないので、ちょっと不便ですが。実行環境がWindowsでもUnixの改行コードで出力する、という変わったプログラムのテストには使える?
追記
改行コードの違いの話ですが、API仕様のJavaDocのFileReaderや関連クラスの解説を見る限りでは、読み込んだ改行文字は文字コードや環境によって変換する、というような記述は見当たらない。どうやら、"result.txt"の改行文字はそのまま読み込まれる、つまり"\r\n"なら、read()は'\r'と'\n'に分けて文字を返すみたい。つまり、このテストコードは"result.txt"の改行コードを使ってテストできるということ。