#不廢話直接看扣!#Flutter 如何開始寫測試-HTTP Request Mocking (feat. Mocktail)?

分享

假設我們的Project中都有一個Call API的Helper,類似這樣:

[lib/Helpers/HttpHelper.dart]
class HttpHelper {
  static String? cableURL;
  static String? host;
  static String remoteHost = 'https://api.matchbox.com.tw';
  static Client http = Client(); // <----- 重點在這

  static Future<Response> doDelete(
      String uri, HttpHeaderVersion v, Map? data) async {
    return await http.delete(Uri.parse('${host!}$uri'),
        body: json.encode(data), headers: v.header());
  }

  static Future<Response> doGet(String uri, HttpHeaderVersion v) async {
    return await http.get(Uri.parse('${host!}$uri'),
        headers: v.header());
  }

  static Future<Response> doPost(
      String uri, HttpHeaderVersion v, Map? data) async {
    return await http.post(Uri.parse('${host!}$uri'),
        body: json.encode(data), headers: v.header());
  }

  static Future<Response> doPut(
      String uri, HttpHeaderVersion v, Map? data) async {
    return await http.put(Uri.parse('${host!}$uri'),
        body: json.encode(data), headers: v.header());
  }
}
[lib/Repositories/AuthRepo.dart]
class AuthRepo {
  Future<User?> fetchCurrentUserData() async {
    final response = await HttpHelper.doGet('/auth',  // <----- 要Mock的URL
        HttpHeaderVersion.v1, null);
    try {
      if (response.statusCode == 200) {
        return User.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
      } else {
        var err = ApiError.fromJson(
            jsonDecode(response.body) as Map<String, dynamic>);
        return Future.error(err.message ?? '');
      }
    } catch (e) {
      return Future.error(e.toString());
    }
  }
}

測試可以這樣寫:

[test/helpers/MockHelper.dart]
class MockHttpClient extends Mock implements HttpClient {}
[test/widgets/MyProfilePage_test.dart]
testWidgets('When Success', (WidgetTester tester) async {
   await _loadWidget(tester);
   HttpHelper.http = MockClient((req) async {
     if (req.url.path == '/auth') {  // <----- 等於AuthRepo中要Mock的URL
       return Response('{"id": 1}', 200);
     }
     return Response('null', 200);
   });
   await tester.tap(find.text('取得個人資料'));
   await tester.pump();
   expect(User.current?.id, 1);
   expect(User.current?.isGuest, isFalse);
});

testWidgets('When Failed', (WidgetTester tester) async {
   await _loadWidget(tester);
   HttpHelper.http = MockClient((req) async {
     if (req.url.path == '/auth') {  // <----- path等於AuthRepo中doGet的URL
       return Response('{"message": "Invalid Token!"}', 403);
     }
     return Response('null', 200);
   });
   await tester.tap(find.text('取得個人資料'));
   await tester.pump();
   expect(find.text('Invalid Token!'), findsOneWidget);
});

重點摘要

  1. 把原本的HttpClient換成MockClient
  2. 找出要Mock的URL
  3. 在測試中回傳期待的Response

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *