Mockitoの最低限な使い方

##はじめに
現在携わっているプロジェクトで**JUnit + Mockito + PowerMock** を使うことになったのですが
そもそもJUnit自体まともに触ったことがないわたしにとって全てが未知の領域。

「**Mockito**」でggってみても、なかなか知識０の人がすぐ使えるようになる説明されている記事が少ない。というか**日本語が少ない！**
日本語で説明がないとなかなか理解できないんですよね。。

ということで、最近ようやく少しだけ飲み込めたので何も知らなかった私に向けてこの記事を書きます。

今回は**Mockito**編です。

特に、テスト対象クラスとは別クラスのメソッドをモック化したい場合について書きます。


##Mockitoにできないこと
まずMockitoには、できないことがたくさんあります。
万能ではなく、モック化できるメソッドは限られるのです。
モック化できないのが

 - **privateメソッド**
 - **staticメソッド**
 - **protectedメソッド**
 - **インスタンス生成(new)**

以上の4種類です。（多分）
あとは抽象クラスなんかもモック化できなかったと思います。(多分)

それ以外であれば基本的にmockitoでモック化することができます（多分）。
上の4つをモック化するには、Mockitoとは別で`PowerMock`を使用しなければいけません。


## 呼び出したいメソッドのあるクラスをモック化
まず、モック化したメソッドを呼び出すにはそのクラスをモック化します。
モック化の方法は**2種類**。どちらか片方だけで大丈夫です。

**① クラス直下に`@Mock`**
**② `mock()`メソッドを使う**
 
```Java:Java

public class TestClass {
  // ① クラス直下に@Mockでモックインスタンスの宣言
  @Mock
  private Entity entity; // これは宣言のみで、モックオブジェクトは生成されない
  
  @Test
  public void test001() {
     // ② mock()メソッドを使う
    Entity entity = mock(Entity.class); // これだけでモックオブジェクトが生成される
  }
}

```
**①**の場合、この宣言とは別に初期化を行う必要があります。
**②**はテストクラスの中で毎度クラスをモック化します。これは初期化の必要はありません。

### モックの初期化
**①**の`@Mock`の場合モックオブジェクトはまだ生成されないので、**初期化する**必要があります。

```Java:Java

public class class() {
  // @Mockのパターン
  @Mock
  private ResultEntity entity;
  
  @Before // @Beforeアノテーションをつけ、各テストメソッドの実行前に毎回実行。
  private void initMocks() {
    MockitoAnnotations.initMocks(this); // 初期化のおまじない
  }
}
```

**①**の方法は、**テストケースが複数ありモック化したいクラスが何度も出てくる場合**に有効かと思います。


## テスト対象クラスにモックを注入
`@InjectMocks`アノテーションを使い、テストクラスの直下でテスト対象クラスにモックを注入します。

```java
public class TestClass {
  @Mock
  Entity entity; // モック化したクラス

  @InjectMocks
  Human human; // テスト対象クラスにモックを注入
}
```

一応これだけでモック化した上でテストを行うことはできるのですが
カバレッジを取得する際は**テスト対象クラスのインスタンスが呼ばれないと100%にならない**ので、カバレッジを100%にする場合は

```java
   @InjectMocks
  Human human = new Human();
```
このように書けば大丈夫です。

これでクラスのモック化ができたので、以下でケース別に実際にメソッドをモック化していきます。

##戻り値のあるpublicなメソッドの場合
`public String`など
この場合、メソッドをモック化する書き方は~~なぜか~~**2種類**あります。

###1.thenメソッド

```java
Mockito.when(モックインスタンス).メソッド(任意の引数).thenReturn(任意の戻り値);
// モックされたクラスのメソッドが呼ばれた時、この戻り値を返すよ
```
これでメソッドはモック化され、実際にメソッドは実行されず任意の戻り値を返すだけのモックとなります。

ちなみに、頭の`Mockito.`は、あってもなくてもどちらでも大丈夫です。
`PowerMock`でも同じような書き方をするため、**同時に使用する場合は使い分ける必要がある**ため、頭につけたほうが分かりやすくなると思います。

###2.doメソッド

```java
Mockito.doReturn(任意の戻り値).when(モックインスタンス).メソッド(任意の引数);
// この戻り値を返すよ、モックされたクラスのメソッドが呼ばれた時
```
①と②、どちらも全く同じ挙動をとります。
以下で説明しますが、**thenメソッドでは対応できない場合がある**ので、doメソッドで統一しておけば間違いないようです。

##戻り値のないpublicvoidなメソッドの場合
`public void` この場合は、**doメソッド**でしか記述できません。

```java
Mockito.doNothing().when(モックインスタンス).メソッド(任意の引数);
// 何も返さないよ、モッククラスのメソッドが呼ばれた時
```
thenNothing()というメソッドは無いようです。


##モック化したメソッドの引数を検証する(ArgumentCaptor)
メソッドはモック化したのでその中を検証する必要はありませんが、モック化した**メソッドに渡す引数は正しいかという検証**は必要いなってくるかと思います。

そんな時に使えるのが`ArgumentCaptor`です。


```java
ArgumentCaptor<型> 変数 = ArgumentCaptor.forClass(型.class);
// forClass()メソッドで、その型の容れ物（変数）をつくるよ
```
### capture()メソッド
上の変数をメソッドのモック化をする時に引数として渡すと、実際に渡される引数をキャプチャして変数に格納しれくれます。
その時に、`capture()`メソッドをつけます。

```java
Mockito.doReturn("戻り値").when(クラス).メソッド(変数.capture());
// forClass()メソッドで、その型の容れ物（変数）をつくるよ
```
これで、変数に実際のソースで渡される引数が格納されました。

####格納されたキャプチャ情報の取得

```java
変数.getValue(); // ①
変数.getAllValues().get(index); // ②
```
このどちらかのメソッドを使うことで、変数の型に応じた値を取得できます。

**①**引数一つだけを検証するのであれば、`getValue()`メソッドで格納された情報を取得できます。

**②**ArgumentCaptorは、**引数に何度も渡すことができ、引数の数だけ結果を格納する**ことができます。(同じ型の場合に限る。)

その場合は配列のような形で格納されるので、`getAllValues()`メソッドでその値全てを取得。`get(index)`でそのうちひとつの値を取得できます。

実際には変数を使い回してしまうと、何番目がどこの引数に渡っているものなのか判断しにくくなるので、基本的には**引数の数だけ`ArgumentCaptor`の容れ物を宣言**したほうが良いと思います。

```java
ArgumentCaptor<String> str = ArgumentCaptor.forClass(String.class);
Mockito.doReturn("戻り値").when(Class).getStr(str.capture());
assertTaht(str.getValue(), is(引数の期待値));
```
使い方としてはこんな感じになると思います。

##モック化したメソッドの呼び出し回数を検証する(verify)

メソッドをモック化すると、実際にはそのメソッドを呼び出さないので、**モック化したメソッドがちゃんと呼ばれているかどうかという検証**も必要になってくるかと思います。

その時に使うのが`verify()`メソッドです。

```java
Mockito.verify(モックインスタンス, times(index)).モックメソッド(引数);
```
`verify()`メソッドの第一引数はモックインスタンス、第二引数に`times()`メソッド、その引数にintで期待値を渡すと、そのメソッドが何回呼ばれたか検証できます。

##戻り値のないメソッドはverify()のみでモック化できる
どういうことかと言いますと

戻り値のないメソッドのモック化は[戻り値のないpublicvoidなメソッドの場合](#戻り値のないpublicvoidなメソッドの場合)で書いた通りなんですが

メソッドの呼び出し回数を検証したい場合には、`doNothing()`、`verify()`両方行う必要はなく、**`verify()`のみで2つ同時に行うことができます。**

同時に行うというよりは、**verify()した時点で戻り値のないメソッドとしてモック化ができている**ということです。

ただ注意したいのは、**戻り値のあるメソッドの場合はverify()でモック化できない**ということです。

verify()は**戻り値をモック化することができない**からです。

```java
// doNothing()でモック化を行わなくても、これだけでok
Mockito.verify(モックインスタンス, times(index)).モックメソッド();
```
ちなみに、上記の場合＋引数の検証をしたい場合は

```java
// doNothing()でモック化を行わなくても、これだけでok
Mockito.verify(モックインスタンス, times(index)).モックメソッド(変数.capture());
```
とすることで、引数もこの時に格納できます。


##最後に
これらを覚えれば、ある程度戦えるようになるのではと思います。
同クラスの他メソッドのモック化、newのモック化なども今後書いていく予定です。


## 参考
[【Java】Mockitoの飲み方（入門）](https://orizuru.io/blog/java/mockito-primer/)