"Status" というキーの値(文字列)とそのときの時間(long)を handleStatus() の引数として渡すようになっています。
public class Utils {
public interface ResultListener {
void onError();
void handleStatus(String status, long time);
}
public static void handleJson(String json, ResultListener listener) {
if (listener == null) {
return;
}
try {
JSONObject obj = new JSONObject(json);
String status = obj.optString("Status");
listener.handleStatus(status, System.currentTimeMillis());
} catch (JSONException e) {
listener.onError();
e.printStackTrace();
}
}
}
まずメソッドが呼ばれるかどうかをテストしましょう。前回紹介したように Mockito.verify() メソッドを使います。
/**
* Status キーがある場合、handleJson() が呼ばれることを確認する
*/
public void testStatusKey() {
Utils.handleJson("{\"Status\":\"hoge1\"}", mockResultListener);
verify(mockResultListener, only()).handleStatus(anyString(), anyLong());
}
handleStatus() は引数として String と long をとるので
verify(mockResultListener, only()).handleStatus();
のように指定することはできません。そこで、「引数の文字列がどんな値であっても気にしない、メソッドが呼び出されているかどうかだけ確かめたい」という場合、anyString() や anyLong() を指定することができます。
String, long 以外にも anyInt(), anyBoolean() などが用意されています。
引数の値をチェックするために、引数に直接文字列を指定することができます。
Status キーの値は正しい値を指定することができますが、long の引数は handleStatus() 内で System.currentTimeMillis() しているため、次のテストは失敗します。
失敗するテスト
/**
* Status キーがある場合 handleJson() が呼ばれ、引数が Status キーの値であることを確認する
*/
public void testStatusKey() {
Utils.handleJson("{\"Status\":\"hoge1\"}", mockResultListener);
verify(mockResultListener, only()).handleStatus("hoge1", System.currentTimeMillis());
}
そこで long は値を検証しないことにして、anyLong() を使って次のように書くとまたまたテストに失敗します。
失敗するテスト
/**
* Status キーがある場合 handleJson() が呼ばれ、引数が Status キーの値であることを確認する
*/
public void testStatusKey() {
Utils.handleJson("{\"Status\":\"hoge1\"}", mockResultListener);
verify(mockResultListener, only()).handleStatus("hoge1", anyLong());
}
実は any〇〇() と実際の値を並記することはできません。any〇〇() を使う場合、実際の値の部分には eq() を使います。
/**
* Status キーがある場合 handleJson() が呼ばれ、引数が Status キーの値であることを確認する
*/
public void testStatusKey() {
Utils.handleJson("{\"Status\":\"hoge1\"}", mockResultListener);
verify(mockResultListener, only()).handleStatus(eq("hoge1"), anyLong());
}
Status キーの値は optString() で取得しているため、Status キーが無い場合は空文字になります。
失敗するテスト
/**
* Status キーが無い場合、handleJson() が呼ばれ引数が空文字であることを確認する
*/
public void testNoStatusKey() {
Utils.handleJson("{\"State\":\"hoge1\"}", mockResultListener);
verify(mockResultListener, only()).handleStatus(eq(""), anyLong());
}
引数をログに出力したいということがあるでしょう。そのためには verify 時に引数をキャッチしておく必要があります。
これを行ってくれるのが ArgumentCaptor です。
ここでは String と long の引数をキャッチしたいので
ArgumentCaptor<String> statusCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<Long> timeCaptor = ArgumentCaptor.forClass(Long.class);
のようにして ArgumentCaptor のインスタンスを作ります。
あとはこの ArgumentCaptor の capture() を引数として渡します。
/**
* Status キーがある場合 handleJson() が呼ばれ、引数が Status キーの値であることを確認する
*/
public void testStatusKey() {
Utils.handleJson("{\"Status\":\"hoge1\"}", mockResultListener);
ArgumentCaptor<String> statusCaptor = ArgumentCaptor
.forClass(String.class);
ArgumentCaptor<Long> timeCaptor = ArgumentCaptor.forClass(Long.class);
verify(mockResultListener, only()).handleStatus(statusCaptor.capture(),
timeCaptor.capture());
String status = statusCaptor.getValue();
long time = timeCaptor.getValue();
assertEquals("hoge1", status);
System.out.println("Status = " + status + ", time = " + time);
}
verify() 後は ArgumentCaptor の getValue() で値を取ることが出来ます。
ArgumentCaptor.capture() と any〇〇() は並記することができます
verify(mockResultListener, only()).handleStatus(anyString(),
timeCaptor.capture());
一方、直接引数を渡す場合とは並記できません。
失敗するテスト
verify(mockResultListener, only()).handleStatus("hoge1",
timeCaptor.capture());
eq() を使えば大丈夫です。
verify(mockResultListener, only()).handleStatus(eq("hoge1"),
timeCaptor.capture());
おはようございます。
返信削除mockit、とても便利ですね!