JUnitで業務中、モックオブジェクトの一種としてMockitoというフレームワークを使っていた際、思った通りにOutputを返してくれず半日溶けたので備忘録。
↓Mockito紹介サイト。
Mockitoの飲み方
###前提
例えば以下のソースにおいてControllerクラスのgetContent
メソッドの引数にnullが入るパターンをテストしたい場合。(コードは上記のサイトから引用・改変しています。)
getContent
はその内部でServiceクラスのgetContentById
を使用するメソッドですが、getContent
直下のロジックだけをテストしたい際、getContentById
内のロジックを気にしたくありません。そこでMockitoを用いてgetContentById
内のロジックによらないI/Oを指定し、クラスごとに独立なテストを行います。
public class Controller
{
private Service service = new Service();
public String getContent(String id) {
String content = service.getContentById(id);
return content;
}
}
public class Service
{
private Map contents = new HashMap();
//コンストラクタ
public Service(){ genContents(); }
//key指定してvalueを返す
public String getContentById(String id) {
String content;
content = contents.get(id);
return content;
}
//コンテンツ作る
public void genContents() {
contents.put("1","Tanaka");
contents.put("2","Saitou");
contents.put("3","Yoshida");
contents.put("4","Suzuki");
}
}
以下ミスコード
public class Test{
Controller controller = new Controller();
//ダミーのserviceを作る、中身は知らん
Service service = mock(Service.class);
// I/Oだけ別途設定
doReturn("Content1").when(service).getContentById(Mockito.anyString());
}
doReturn
から始まる文は
「任意のString型を引数として呼び出されたらいつでもContent1という文字列を返せ」
という意味ですが、今回の想定だとgetContentId
の引数がnullなのでanyString()が指定されずgetContentは何も返してくれません。そこで、より広義の引数を指定してやります。
以下正しいコード
doReturn("Content1").when(service).getContentById(Mockito.any());
これでgetContentByIdメソッドに
「なんでもいいから呼び出されたらContent1という文字列を返せ」
という設定を加えることが出来ます。引数がnullでも動かすことが出来ました。
実際の業務ではMockito.Any~()
ではなくてArgumentMatchers.any(~~~.class)
を用いて自作の型引数を持つメソッドに対してモックしていたのですが、今回はより簡単にString型のパターンで書いてみました。
追記
※書いてたらより端的な記事を発見してしまいました。こちらもあわせてどうぞ。
MockitoでMockする際の引数にMockito.anyStringを使う場合の注意点