【Spring】Mockit利用した単体テストの方法

Mockitoとは

Mockitoとはテスト対象クラスが依存しているクラスを簡単にモック化する機能を提供しているライブラリです。mockit公式ページ

Mockitoを利用することでテスト対象クラスの単体テストに集中することができます。依存先のクラスが未実装であったり、外部サービスやDBアクセスなどを行っている場合には特に便利です。

Spring Bootを使用している場合、spring-boot-starter-test内に含まれているため簡単に利用可能です。

Mockitoを使ったテストの例

準備

テストの準備として以下のクラスを作成します。今回はMockitoの使用方法を説明するための例なので商品をidで検索するfindByIdメソッドをItemServiceクラスとItemRepositoryクラスに作成します。

  • Item: 商品情報を格納する。
  • ItemService: 商品情報を処理する。今回のテスト対象クラス。
  • ItemRepository: 商品情報のDB処理を行う。今回モック化するクラス。

動作検証を行った環境は以下の通りです。

  • Java11
  • Spring Boot 2.1.11

テストのためにクラスのコードを以下の様に作成します。import文は省略しています。

Itemクラス

// Lombokを使用
@Value
public class Item {

    private int id;
    private String itemName;
    private int price;
}

ItemServiceクラス

ItemServiceクラスはItemRepositoryクラスへ依存しています。通常の実行時にはItemRepositoryクラスのインスタンスはDIコンテナによってインジェクションされます。

@RequiredArgsConstructor
@Service
public class ItemService {

    // ItemServiceクラスがインジェクションされる。
    private final ItemRepository itemRepository;

    public Item findById(int id) {

        return itemRepository.findById(id);
    }
}

@RequiredArgsConstructorを付与してフィール変数にfinalを指定することでコンストラクタインジェクションを行っています。この記述方法については以下の記事に書いています。

ItemRepositoryクラス

@Repository
public class ItemRepository {

    public Item findById(int id) {
        return null;
    }
}

テストコードの作成

ItemRepositoryクラスをモック化してItemServiceを単体テストするテストコードは以下のようになります。

// 1. jUnitでMockitを使用する
@RunWith(MockitoJUnitRunner.class)
public class ItemServiceTest {

    // 2. 対象クラスのインスタンス作成と@Mockを付けたクラスをインジェクションする
    @InjectMocks
    private ItemService itemService;

    // 3. モック化対象
    @Mock
    private ItemRepository itemRepository;

    @Test
    public void test() {

        // 4.モック化したメソッドの動作を設定する。
        int id = 1;
        when(itemRepository.findById(id)).thenReturn(new Item(1, "MockItem", 100));

        var item = itemService.findById(1);

        // 5. モック化されたオブジェクトの値を検証
        assertThat(item.getId()).isEqualTo(1);
        assertThat(item.getItemName()).isEqualTo("MockItem");
        assertThat(item.getPrice()).isEqualTo(100);
    }
}

1. jUnitでMockitoを使用するためにテストクラスに@RunWith(MockitoJUnitRunner.class)を付与します。

2. モック化したクラスをインジェクションしたいテスト対象クラスに @InjectMocksを付与することでテスト対象のクラスのインスタンを生成します。また、テスト対象クラスが依存しているクラスに@Mockが付与されている場合にモック化されたオブジェクトがインジェクションされます。

この例ではモック化されたItemRepositoryクラスがインジェクションされます。

3. モック化したいクラスに@Mockを付与します。

4. テスト実行時の動作を指定します。この例ではfindByIdの引数に1が渡された時にidが1, itemNameがMockItem, priceが100のItemオブジェクトを返すように指定しています。

この様にMockitoで用意されているwhen、thenReturnなどを使用しテスト時の動作を設定します。thenReturnのかわりにthenThrowを使用して例外を投げることもできます。詳細は公式ドキュメントを参照してください。Mockito公式ドキュメント

5. Mockitoの動作検証のため想定通りにモック化されているかを検証しています。

まとめ

Mockitoを利用することビジネスロジックを実装しているクラスの単体テストが簡単に作成できる様になります。特に外部のAPIやDBアクセスを行っているクラスへ依存しているクラスの単体テストにはモックオブジェクトが必要になるのでMockitoを使用することをお勧めします。