Posted at

HTTP通信するWidgetをテストする(Flutter)

ここ最近、Flutterを使ったクロスプラットフォームのアプリを作ろうドキュメントを片手にと勉強しています。その中でハマった、HTTP通信が含まれるWidgetのテスト方法について書き残します。最終的には以下のコードでテストが成功します。

import 'package:flutter/material.dart';

import 'package:flutter_test/flutter_test.dart';
import 'package:http/testing.dart';
import 'package:http/http.dart';

class Test extends StatelessWidget {
Client client = Client();

@override
Widget build(BuildContext context) {
return MaterialApp(
home: FutureBuilder(
future: getWord(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) return CircularProgressIndicator();
return Text(snapshot.data);
}
),
);
}

Future<String> getWord() async {
final response = await client.get('http://example.com');
return response.body;
}
}

void main() {
testWidgets('http mock', (WidgetTester tester) async {
final mockClient = MockClient((_) async => Response('Hello World', 200));
final test = Test();
test.client = mockClient;

await tester.pumpWidget(test);
await tester.pumpAndSettle();
expect(find.text('Hello World'), findsOneWidget);
});
}

やっていることはHTTPクライアントをモックに差し替えてからテストする、これだけです。因みにパッケージは次の通りです。


pubspec.yaml

dependencies:

flutter:
sdk: flutter
http: ^0.12.0+2

dev_dependencies:
flutter_test:
sdk: flutter
mockito: ^4.1.0


それでは、順を追って説明していきます。


Widgetの作成

まずはテスト対象のWidgetを作成します。APIからのレスポンスを表示するだけのWidgetです。レスポンスを待ってからWidgetをビルドしたかったため、FutureBuilderを使用しています。このclientの中身をモッククライアントに差し替えることが今回の肝です。

class Test extends StatelessWidget {

Client client = Client();

@override
Widget build(BuildContext context) {
return MaterialApp(
home: FutureBuilder(
future: getWord(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) return CircularProgressIndicator();
return Text(snapshot.data);
}
),
);
}

Future<String> getWord() async {
final response = await client.get('http://example.com');
return response.body;
}
}


モッククライアントの作成

Clientを差し替えるためのモックを作成します。httpパッケージに用意されているモック作成用のMockClientクラスを利用します。ここでは、MockClientのレスポンスが'Hello World'と200ステータスを返すように設定しています。今回は、単純にレスポンスの表示するだけですが、テストの内容によってはJSONを返すようにしたり、目的に合わせてレスポンスを設定することができます。

final mockClient = MockClient((_) async => Response('Hello World', 200));


テストの実行

ここまでで、Widgetとモッククライアントができました。あとはテストを実行するだけです。Testウィジェトのインスタンスを生成して、インスタンスのclientの中身をmockClientに差し替えます。最後にtester.pumpWidgetでWidgetをビルドし、tester.pumpAndSettleでFutureBuilderが生成する「Hello World」が表示されるのを待つことでテストが成功します。

testWidgets('print test', (WidgetTester tester) async {

final mockClient = MockClient((_) async => Response('Hello World', 200));
final test = Test();
test.client = mockClient;

await tester.pumpWidget(test);
await tester.pumpAndSettle();
expect(find.text('Hello World'), findsOneWidget);
});

以上が、HTTP通信するWidgetのテスト方法についての記事でした。お役に立てたら幸いです!