Map→List時にMethodが呼ばれたかをMockitoで確認する(when,verify)

Stubにしたメソッドが決められた引数で呼ばれているのかをMockitoのverifyを使うことで確認することができるが、Mapを使用しているときはランダムになるため普通のverifyでは通用しなくなるのでArgumentMatcherのargThatを使用して引数の検証を行う。

## <u>Maven</u>
[ArgumentMatcherのargThat](https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter)を使用できるように、Dependencyをpom.xmlに追加しておく。

## <font color="Black"><u>例えば...</u></font>
```java
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor // コンストラクタを使用せずにGodRepositoryをAutowiredする
public class GodServiceImpl implements GodService {

  private final GodRepository godRepository; // RequiredArgsConstructorを使用する時はfinalにする

  @Override
  public void update(Map map) {
    List<String> updateList = new ArrayList<>(map.keySet()); // 順番がランダムなListになる
    godRepository.update(updateList);
  }
}
```
のテストを以下のように作成して

```java
import static java.util.Arrays.asList;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.HashMap;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class) // 必要な設定等省略する
class GodServiceImplTest {

  private GodService godService;

  @Mock
  private GodRepository godRepository;

  @BeforeEach
  public void setUp() {
    godService = new GodServiceImpl(godRepository); // MockしたGodRepositoryをInjectする
  }

  @Test
  void update() {
    when(godRepository.update(asList("2a", "3b", "1c", "4d"))).thenReturn(4);

    Map<String, String> updateMap = new HashMap<>();
    updateMap.put("2a", "1");
    updateMap.put("3b", "2");
    updateMap.put("1c", "3");
    updateMap.put("4d", "4");
    godService.update(updateMap);

    verify(godRepository).update(asList("2a", "3b", "1c", "4d"));
  }
}
```
テストを実行すると

```
org.mockito.exceptions.misusing.PotentialStubbingProblem: 
Strict stubbing argument mismatch. Please check:
 - this invocation of 'update' method:
    godRepository.update([4d, 1c, 2a, 3b]);
```
引数の順番が違うと言われる。

## <font color="Black"><u>ArgumentMatcher</u></font>
そこでArgumentMatcherのargThatを使用して引数の検証も行う。

```java
import static java.util.Arrays.asList;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.HashMap;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class) // 必要な設定等省略する
class GodServiceImplTest {

  private GodService godService;

  @Mock
  private GodRepository godRepository;

  @BeforeEach
  public void setUp() {
    godService = new GodServiceImpl(godRepository); // MockしたGodRepositoryをInjectする
  }

  @Test
  void update() {
    // containsAllだけでは引数が3つでも通過してしまうのでsizeで回避する
    when(godRepository.update(argThat(list -> list.size() == 4 &&
        list.containsAll(asList("2a", "3b", "1c", "4d"))))).thenReturn(4);

    Map<String, String> updateMap = new HashMap<>();
    updateMap.put("2a", "1");
    updateMap.put("3b", "2");
    updateMap.put("1c", "3");
    updateMap.put("4d", "4");
    godService.update(updateMap);

    verify(godRepository).update(argThat(list -> list.size() == 4 &&
        list.containsAll(asList("2a", "3b", "1c", "4d"))));
  }
}
```