Groovy/Maven/Java + TestNG Example ではGroovyを使うことでJavaのprivateフィールドを簡単に参照・更新出来ることを紹介しました。
そこで、より実用的なシーンとしてxUnit等による単体テストの作成でしばしばぶつかる、JavaのSingletonデザインパターンのmock/stub化をGroovyで攻略してみます。
サンプルコードは以下のGistにUPしています。
以下のようなディレクトリ構成になります。
gjt3/
pom.xml
src/
main/java/gjt3/Singleton.java
test/groovy/gjt3/SingletonTest.groovy
Singleton.javaはSingletonの手抜き実装です。privateなコンストラクタにgetInstance()経由で文字列を渡して、インスタンスを区別出来るようにしてます。
Groovy + TestNGで組み立てたテストコードの内容を紹介します。
// 最初の2つは、通常のSingletonの動作確認です。
Singleton s1 = Singleton.getInstance("s1");
Assert.assertEquals(s1.getArg(), "s1");
// getInstance()したのは、上で初期化した"s1"を返すはずです。
Singleton s2 = Singleton.getInstance("s2");
Assert.assertEquals(s2.getArg(), "s1");
// Groovyでprivateなコンストラクタを呼び出しインスタンス化します。
Singleton s3 = new Singleton("s3");
Assert.assertEquals(s3.getArg(), "s3");
// これを、privateなSingletonインスタンス保管用のフィールドにセットします。
Singleton.instance = s3;
// getInstance()してみると、上で上書きした"s3"のインスタンスが返されます。
Singleton s4 = Singleton.getInstance("s4");
Assert.assertEquals(s4.getArg(), "s3");
当然ですがテストはpassします。
ただし注意点として、SingletonはClassのフィールドにセットされますので、テストコード中でこれを弄った後は、必ず元のインスタンスに戻しておく必要があります。テストコード中でmock用のインスタンスに差し替え、そのままにしてしまうと、後に続くテストコードが失敗する可能性があります。