You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Mockito对Flutter中Dio实现的登录认证POST请求做单元测试?

Flutter Dio登录认证请求单元测试Mock示例

问题场景

使用Dio实现Flutter登录认证POST请求后,编写单元测试时,通过Mockito Mock Dio的post方法时,不清楚该返回何种响应,无法完成Mock操作,需要针对该场景的详细单元测试示例。

登录认证请求代码

Future<String?> authentication(String mobileNumber, String password, Dio dio) async {
  dynamic data = {
    "username": mobileNumber,
    "password": password,
    "grant_type": "password",
    "client_id": "client_id"
  };

  try {
    final response = await dio.post(baseurl, // 注:原代码中_dio应为传入的dio参数
        data: data,
        options: Options(headers: {
          "Content-Type": "application/x-www-form-urlencoded"
        }));
    if (response.statusCode == 200) {
      accessToken = response.data["access_token"];
      refreshToken = response.data["refresh_token"];
      Fluttertoast.showToast(msg: "Successfully Logged in");
      return accessToken;
    }
  } on DioError catch (e) {
    Fluttertoast.showToast(msg: "Something went wrong");
    return e.toString();
  }
  return accessToken;
}

完整单元测试实现

确保已添加依赖:mockito、flutter_test,并通过flutter pub run build_runner build生成Mock类。

成功场景测试

import 'package:dio/dio.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';

// 通过mockito生成的MockDio类
class MockDio extends Mock implements Dio {}

void main() {
  late MockDio mockDio;
  late YourAuthService service; // 替换为你的认证服务类

  setUp(() {
    mockDio = MockDio();
    service = YourAuthService(); // 初始化你的服务类
  });

  test("认证成功时返回token", () async {
    // 构造Dio成功响应
    final mockResponse = Response(
      requestOptions: RequestOptions(path: Apiservices().baseurl),
      statusCode: 200,
      data: {
        "access_token": "test_token_123",
        "refresh_token": "refresh_token_456"
      },
    );

    // Mock Dio的post方法,匹配请求参数
    when(mockDio.post(
      Apiservices().baseurl,
      data: {
        "username": "username",
        "password": "password",
        "grant_type": "password",
        "client_id": "client_id"
      },
      options: anyNamed('options'),
    )).thenAnswer((_) async => mockResponse);

    // 执行测试
    final result = await service.authentication("username", "password", mockDio);

    // 验证结果
    expect(result, "test_token_123");
    expect(result, isA<String>());
    // 验证Dio的post方法被调用一次
    verify(mockDio.post(
      Apiservices().baseurl,
      data: anyNamed('data'),
      options: anyNamed('options'),
    )).called(1);
  });
}

错误场景测试(Dio请求失败)

test("认证失败时返回错误信息", () async {
  // 构造Dio错误
  final mockDioError = DioError(
    requestOptions: RequestOptions(path: Apiservices().baseurl),
    response: Response(
      requestOptions: RequestOptions(path: Apiservices().baseurl),
      statusCode: 401,
      data: {"error": "Invalid credentials"},
    ),
    type: DioErrorType.response,
  );

  // Mock Dio的post方法抛出错误
  when(mockDio.post(
    Apiservices().baseurl,
    data: anyNamed('data'),
    options: anyNamed('options'),
  )).thenThrow(mockDioError);

  // 执行测试
  final result = await service.authentication("wrong_user", "wrong_pass", mockDio);

  // 验证结果
  expect(result, mockDioError.toString());
  verify(mockDio.post(
    Apiservices().baseurl,
    data: anyNamed('data'),
    options: anyNamed('options'),
  )).called(1);
});

关键说明

  • 构造Dio Response:必须实例化Response类,至少指定requestOptions(必填项,传入请求路径)、statusCode和data参数。
  • Mock匹配规则:若需严格验证请求参数,可在when中明确指定匹配条件;无需精确匹配时,用anyNamed('data')等模糊匹配。
  • Mock类生成:必须通过build_runner工具生成MockDio类,否则会出现未定义类的错误。

内容的提问来源于stack exchange,提问作者Rafi Muhd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 02:40:27