見出し画像

[Flutter]Mockitoを使ったユニットテスト

FlutterのMockitoパッケージを使ったユニットテストの書き方についてご紹介します!

Mockitoとは?

Flutterでのユニットテストに使用されるモックフレームワークで、モックとは実際のオブジェクトをテスト環境で代替するものです。
オブジェクトの振る舞いを模倣(もしくはモック)し、正しく機能しているかどうかを独立してテストすることができます。

テストの種類とその違い

テストにはいくつかの種類があり、それぞれが異なる目的と範囲を持っています。

  • ユニットテスト: システムの最小単位(一般的には関数またはメソッド)をテストします。Mockitoはこのユニットテストによく使われます。

  • 統合テスト: システムのさまざまな部分が互いに適切に動作するかを確認するためのテストです。個々のユニットが適切に機能するだけでなく、それらが一緒に動作することも確認します。

  • システムテスト: システム全体が期待通りに動作するかを確認します。

Mockitoを使ったFlutterのコード例

それでは、具体的にどのようにMockitoをFlutterで使用するか見てみましょう。
今回は、HTTPリクエストを行うNetworkServiceというサービスをテストするための例を示します。
この例では、http.Clientクラスのモックを作成し、NetworkServiceがHTTPリクエストを正しく扱うかどうかをテストします。

フォルダ構成は以下。
flutter create <your_project>で作成したFlutterのプロジェクトにおいて、libとtestのディレクトリが最初から作成されているので、そこに各dartファイルを作成しています。

your_project/
|-- lib/
|   |-- network_service.dart
|   |-- main.dart  
|-- test/
|   |-- network_service_test.dart
|   |-- mock_http_client.dart
|   |-- mock_http_client.mocks.dart  # (このファイルはbuild_runnerによって自動生成)
|-- pubspec.yaml

必要なパッケージをpubspec.yamlに追加します。

dev_dependencies:
  flutter_test:
    sdk: flutter
  mockito: ^5.0.0
  build_runner: ^2.0.4
  http: ^0.13.3

network_service.dartにテスト対象のNetworkServiceクラスを書きます。

import 'package:http/http.dart' as http;

class NetworkService {
  final http.Client client;

  NetworkService({required this.client});

  Future<String> fetchData(String url) async {
    final response = await client.get(Uri.parse(url));

    if (response.statusCode == 200) {
      return response.body;
    } else {
      throw Exception('Failed to load data');
    }
  }
}

mock_http_client.dartにモッククラスを定義します。

import 'package:mockito/annotations.dart';
import 'package:http/http.dart' as http;

@GenerateMocks([http.Client])
class MockHttpClient {}

ここで書かれている@GenerateMocksとは、テストで利用するためのモッククラスを自動的に生成するために使用するアノテーションです。
以下のコマンドをターミナルで実行すると、自動でmock_http_client.mocks.dartが作成されます。

flutter pub run build_runner build

次に、network_service_test.dartに実際のテストコードを書きます。

import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;
import 'package:mockito/mockito.dart';
import 'package:test_mock/network_service.dart';

import 'mock_http_client.mocks.dart'; // 自動生成されたモッククラスのインポート

void main() {
  late NetworkService networkService;
  late MockClient mockHttpClient;

  setUp(() {
    mockHttpClient = MockClient();
    networkService = NetworkService(client: mockHttpClient);
  });

  test('fetchData returns data if the http call completes successfully',
      () async {
    // http.Clientのモックを設定
    when(mockHttpClient.get(any))
        .thenAnswer((_) async => http.Response('mock data', 200));

    // fetchDataメソッドをテスト
    expect(await networkService.fetchData('dummy_url'), 'mock data');
  });

  test('fetchData throws an exception if the http call completes with an error',
      () {
    // http.Clientのモックを設定
    when(mockHttpClient.get(any))
        .thenAnswer((_) async => http.Response('Not Found', 404));

    // fetchDataメソッドをテスト
    expect(networkService.fetchData('dummy_url'), throwsException);
  });
}

このコードはNetworkServiceがHTTPリクエストを正しく扱うかをテストします。
もしHTTPリクエストが成功(ステータスコード200)すれば、レスポンスデータが返されるはずです。
もしHTTPリクエストが失敗すれば(ステータスコードが200以外)、例外がスローされるはずです。これらの振る舞いが正しいかをテストします。

以下のコマンドを実行して、All tests passed!と表示されたらテスト成功です。

$ flutter test test/network_service_test.dart
00:03 +2: All tests passed!                                

ちなみにvscodeを使っているなら、書いたtestの上にDebugというボタンが出ているので押すと、flutter testを実行したのと同じ結果が画面下部のDebug consoleに表示されるので便利です。

Debug

まとめ

Flutterでのユニットテストは、アプリケーションの品質を保つための重要なプロセスです。ユニットテストは、コードの一部分が期待通りに動作していることを確認し、問題が発生した場合にはそれを特定しやすくします。Mockitoはこのプロセスを助けてくれるので非常に便利です。

この記事が気に入ったらサポートをしてみませんか?