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

使用Mocktail验证含MultipartFile的Dio POST请求时遇到错误的问题求助

使用Mocktail验证含MultipartFile的Dio POST请求时遇到错误的问题求助

大家好,我最近在测试一个包含MultipartFile的Dio POST请求方法,用Mocktail做调用验证时碰到了棘手的问题,想请教下有没有解决思路。

问题背景

我要测试的loginUser方法,会根据传入的参数构建带MultipartFile(有图片时)的FormData,再通过Dio发送请求。没有图片参数时,Mocktail的verify验证完全正常,但一旦加入MultipartFile的验证逻辑,就出现了两种不同的错误。

两种错误情况

  1. 在verify回调中使用async/await时的错误
    为了匹配实际代码中await处理MultipartFile的逻辑,我在verify里也加了async/await,结果抛出以下错误:

    Used on a non-mocktail object
    
    package:matcher                                                         fail
    
    package:mocktail/src/mocktail.dart 522:7                                _makeVerify.<fn>
    
    test\features\auth\data\datasources\remote_data_source_test.dart 69:15  main.<fn>.<fn>.<fn>
    
  2. 不使用async/await时的错误
    如果去掉verify里的await,MultipartFile就会以Future对象的形式存在,和实际代码中await后的实例不匹配,导致验证失败,错误信息如下:

    No matching calls (actually, no calls at all).
    
    (If you called `verify(...).called(0);`, please instead use `verifyNever(...);`.)
    
    package:matcher                                                         fail
    
    package:mocktail/src/mocktail.dart 728:7                                _VerifyCall._checkWith
    
    package:mocktail/src/mocktail.dart 519:18                               _makeVerify.<fn>
    
    test\features\auth\data\datasources\remote_data_source_test.dart 69:15  main.<fn>.<fn>.<fn>
    

相关代码

测试代码

test("It should post loginUser and return void by calling only once", () {
  //Arrange
  when(() => dio.post(
        any(),
        data: any(named: "data"),
      ))
      .thenAnswer((invocation) async => Response(
            requestOptions: RequestOptions(),
            statusCode: 201,
            data: {"message": "user logged in sucessfully"}));

  //Act
  final response = remoteDatasource.loginUser(
      name: params.name,
      phoneNumber: params.phoneNumber,
      countryCode: params.countryCode,
      image: params.image);

  //Assert
  expect(response, completes);
  verify(() async => dio.post(dio.options.baseUrl + loginUrl,
          data: FormData.fromMap({
        "image": params.image != null
            ? await MultipartFile.fromFile(params.image!.path,
                filename: imageFileName)
            : null,
        "name": params.name,
        "phoneNumber": params.phoneNumber,
        "countryCode": params.countryCode
      }))).called(1);
  verifyNoMoreInteractions(dio);
});

实际业务代码

Future<void> loginUser(
    {required String name,
    required int phoneNumber,
    required String countryCode,
    File? image}) async {
  try {
    final String url = _dio.options.baseUrl + loginUrl;
    final data = {
      'image': image != null
          ? await MultipartFile.fromFile(
              image.path,
              filename: imageFileName,
            )
          : null,
      "name": name,
      "phoneNumber": phoneNumber,
      "countryCode": countryCode
    };
    final response = await _dio.post(
      url,
      data: FormData.fromMap(data),
    );
    print(url.toString());
    if (response.statusCode == 200 || response.statusCode == 201) {
      return;
    } else {
      throw ApiException(
          message: response.data.message,
          statusCode: response.data.statusCode);
    }
  } on DioException catch (dioException) {
    throw ApiException(
        message: dioException.error.toString(), statusCode: 500);
  } catch (e) {
    throw ApiException(message: e.toString(), statusCode: 500);
  }
}

补充说明:params和dio对象在无图片参数的场景下都能正常工作,只有当需要验证MultipartFile时才会触发上述错误。

备注:内容来源于stack exchange,提问作者Sheraz Asghar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.20 09:59:36