kagamihogeの日記

kagamihogeの日記です。

コンストラクタが private なクラスをモックで差し替えてテストしたかった

最近ようやくテストコードを書くことに目覚め始めました。

で、まぁ、とあるクラスをテストしようと思ったが、一部にミドルウェアと通信する箇所があるので、そこはユニットテストのときはなんもしないようにしたかった。DI なんて便利なモノがまだ無い環境なので、インスタンス生成のメソッドを protected にして、ユニットテストするときはモッククラスを返す、というやり方を試みた。

コード的にはこんな感じ。

//テストしたいクラス
public class Hoge {
	public void hogeMethod() {
		//いろいろなコード
		MiddlewarePiyo piyo = createMiddlewarePiyo();
		middleware.piyoMethod();//ミドルウェアとごにょごにょする
		//いろいろなコード
	}
	
	protected MiddlewarePiyo createMiddlewarePiyo() {
		return MiddlewarePiyo.getInstance();
	}
}

public class HogeTest {
	@Test
	public void testHogeMethod() {
		Hoge h = new HogeMock();
		h.hogeMethod();
		assert(...
	}

	private class HogeMock extends Hoge {
		@Override
		public MiddlewarePiyo createMiddlewarePiyo() {
			return new MiddlewarePiyo() {
				@Override
				public void piyoMethod() {//ユニットテスト時は何もしなくする
				}
			}
		}
	}	
}

と、ここまで書いて HogeMock がコンパイルエラー。The constructor xxxx() is not visible. って、えー? まじっす? と思って Piyo クラスのコンストラクタをチェックしてみると……

public class MiddlewarePiyo {
	private MiddlewarePiyo() {}

コンストラクタが private 指定されていた……そりゃ not visible ですわな。ユニットテストのためにスコープを protected に変えたいのだけど、ソースは見れてもいじる権限が無いのでいかんともしがたい。そういえば WEwLC 本でも Singleton まわりは色々書いてあったよなぁーと思いつつ、一応 static factory method も見てみる。

public class MiddlewarePiyo {
	private MiddlewarePiyo() {}
	public static MiddlewarePiyo getInstance() {
		return new MiddlewarePiyo();
	}
}

Singleton ですらなかった。単に static factory method でコンストラクタに名前持たせたかっただけっぽいなー。

あきらめきれずに色々ぐぐったが、基本的にはコンストラクタのスコープゆるめればいいっしょ、というコメントがほとんど。Testing a class with private constructor をみると JUnit-addons なるものがあり PrivateAccessor を使えばいけるんじゃね? 的なことが書いてあるが……こいつは 3.7 and JUnit 3.8.x 対応までで止まってるっぽい。

うーん、だめかー……