[Java]それCollectionsのnCopies()を使えば良くない？

例えば、件数が膨大なリストを受け取って処理をするメソッドがあるとします。そのメソッドのテストコードを書きたい場合、リストをどのように準備すれば良いでしょうか？
※ここでは、リストの内容は関係なく、リストの件数によって処理が変わる部分のみテストしたいとします。

200件のリストを作りたい場合、愚直にやると、for文やラムダ式で作ることになります。
```java
    // for文
    List<String> member = new ArrayList<>();
    for (int i = 0; i < 200; i++) {
      member.add(String.valueOf(i));
    }

    // ラムダ式
    List<String> member = IntStream.range(0, 200).mapToObj(String::valueOf).toList();
```
でも、もっと簡単に作る方法があるんです。

実際のユースケースで確認してみましょう。

# プロダクトコード
ある複数人のメンバーを10人組のグループにして、グルーピングした結果をコンソールに出力するという簡単なプログラムがあるとします。

| メソッド | 役割 |
|:-:|:-:|
| groupingMember()  | membersを10人組のグループに分割し、<br>グループ単位にannounceGroup()を呼び出す  |
| announceGroup()  | 引数のgroupをコンソールに出力する  |

```java:GroupingService.java
@Service
public class GroupingService {

  private static int count = 1;

  /*
  メンバーを受け取りランダムにグループ分けをする.
 */
  public void groupingMember(List<String> members) {
    // 10人組のグループを作成する.
    ListUtils.partition(members, 10).forEach(this::announceGroup);
  }

  /*
    グループメンバを発表する.
   */
  public void announceGroup(List<String> group) {
    System.out.println("第" + count + "グループ: " + group);
    count++;
  }

}
```

- ここでは、リストを指定単位で分割できる`ListUtils.partition(members, 10)`という便利メソッドを使っています。詳しくはこちら⏬

https://qiita.com/toranoko92114/items/ffa9105f46c2928f8492


このプロダクトコードにおいて、きちんと10人組にグルーピングがされ、その結果、`announceGroup()`が想定回数呼ばれているか、という回数に着目したテストがしたいとします。

ex. メンバが50人だったら、10人組にグルーピングすると、`announceGroup()`は5回呼ばれる.

どのようなテストコードになるでしょうか？

# テストコード
プロダクトコードにおいて、きちんと10人組にグルーピングがされ、その結果、`announceGroup()`が想定回数呼ばれているか、を確認するテストコードを書きます。

```java:GroupingServiceTest.java
@Import({GroupingService.class})
@ExtendWith(SpringExtension.class)
public class GroupingServiceTest {

  @SpyBean
  private GroupingService sut;

  @ParameterizedTest
  @MethodSource("provider_members")
  void 決められた人数ごとにきちんとグルーピングされグループ発表メソッドが想定回数呼ばれているか(
      List<String> members, int expectedCallCount) {
    // 実行
    sut.groupingMember(members);
    // 検証
    Mockito.verify(sut, Mockito.times(expectedCallCount)).announceGroup(anyList());
  }

  private static Stream<Arguments> provider_members() {
    return Stream.of(
        // memberが150人いたら15グループできる
        Arguments.of(Collections.nCopies(150, "名前"), 15),
        // memberが200人いたら20グループできる
        Arguments.of(Collections.nCopies(200, "名前"), 20)
    );
  }
}
```
- 本テストコードは、`@ParameterizedTest`と`@MethodSource("provider_members")`によって、`provider_members`で定義した引数（`members`を`expectedCallCount`）を受け取って、処理を行います。

- `Mockito.verify(sut,Mockito.times(expectedCallCount)).announceGroup(anyList());`によって、プロダクトコードの`announceGroup()`が何回呼ばれたかをテストすることができます。


## ポイント
テストコードのメソッドに引数として渡すリストを準備しています。そこで、for文でもラムダ式でもない、`Collections.nCopies()`という関数を使っています。こうすることで、たった1行で150件とか200件のリストを作ることができます。
```java
// memberが150人いたら15グループできる
Arguments.of(Collections.nCopies(150, "名前"), 15),
// memberが200人いたら20グループできる
Arguments.of(Collections.nCopies(200, "名前"), 20)
``` 

> nCopies​(int n, T o) 
指定されたオブジェクトのn個のコピーで構成される不変のリストを返します。

https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Collections.html

#　テスト結果
テストを実行してみましょう。きちんと想定どおりテストが成功しています🙌
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630308/042329cd-e05b-d4e4-80d3-b4a827e88d7d.png)

# まとめ
リストの内容には着目せず、ただただ膨大な件数のリストを作りたい場合は、for文とかではなく、`Collections.nCopies()`関数を使うのがオススメです！

```java:sample
List<String> names = Collections.nCopies(150, "名前")
```
これで150件のリストが作られます。

以上です。