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

Flutter单元测试Mock Http请求报错:Null无法转为Future<Response<dynamic>>

解决Mockito单元测试报错 type 'Null' is not a subtype of type 'Future<Response<dynamic>>'

核心问题分析

报错的直接原因是Mockito的mock匹配失败,导致mockApiConnect.get()返回null,而非预期的Future<Response>。同时HomeProvider.getUser()的异步逻辑也存在问题,即便mock正常工作,也会返回空列表。

问题1:Mock的URL参数不匹配

HomeProvider.getUser()中调用的是api.get(EndPoints.user, ...),但测试代码里写的是:

when(mockApiConnect.get(EndPoints.baseUrl, headers: {"app-id": "myAppID"}))

URL参数不一致,Mockito无法匹配到对应的mock方法,因此返回null。

问题2:HomeProvider.getUser()异步逻辑错误

使用.then()处理Future但未等待其完成就直接返回空列表user,导致测试拿到的是未填充数据的空列表,同时会隐藏潜在错误。

问题3:泛型方法的Mock匹配(可选但重要)

ApiConnect.get()是泛型方法,Mockito处理泛型时需明确类型,否则可能出现匹配问题。


修复步骤

1. 修正Mock的URL参数

将测试中的EndPoints.baseUrl改为EndPoints.user,与实际调用保持一致:

when(mockApiConnect.get(EndPoints.user, headers: {"app-id": "myAppID"}))
    .thenAnswer((_) async => Response(body: response, statusCode: 200));

2. 修复HomeProvider.getUser()的异步逻辑

改用await等待API请求完成后再返回数据,同时优化错误处理:

Future<List<User>> getUser() async {
  try {
    final response = await api.get(EndPoints.user, headers: {"app-id": "myAppID"});
    return (response.body['data'] as List).map((value) => User.fromJson(value)).toList();
  } catch (error) {
    print(error.toString());
    return []; // 也可抛出错误交由上层处理
  }
}

3. 优化泛型方法的Mock(可选)

若仍存在泛型匹配问题,可明确指定泛型类型或使用any匹配参数:

// 方式1:明确泛型类型
when(mockApiConnect.get<dynamic>(EndPoints.user, headers: {"app-id": "myAppID"}))
    .thenAnswer((_) async => Response(body: response, statusCode: 200));

// 方式2:使用any匹配参数(参数不确定时)
when(mockApiConnect.get(any, headers: anyNamed('headers')))
    .thenAnswer((_) async => Response(body: response, statusCode: 200));

完整修复后的测试代码

import 'package:flutter_test/flutter_test.dart';
import 'package:get/get_connect/http/src/response/response.dart';
import 'package:mockito/mockito.dart';
import 'package:trial/app/data/api/api_connect.dart';
import 'package:trial/app/data/model/user.dart';
import 'package:trial/app/data/provider/home_provider.dart';
import 'package:trial/app/utils/constants.dart';

class MockApiConnect extends Mock implements ApiConnect {}

void main() {
  group('HomeProvider', () {
    late HomeProvider homeProvider;
    late MockApiConnect mockApiConnect;

    setUp(() {
      mockApiConnect = MockApiConnect();
      homeProvider = HomeProvider();
      homeProvider.api = mockApiConnect;
    });

    test('getUser returns list of users on success', () async {
      // arrange
      final response = {
        'data': [
          {'id': 1, 'firstName': 'John Doe'},
          {'id': 2, 'firstName': 'Jane Doe'}
        ]
      };
      when(mockApiConnect.get<dynamic>(EndPoints.user, headers: {"app-id": "myAppID"}))
          .thenAnswer((_) async => Response(body: response, statusCode: 200));

      // act
      final result = await homeProvider.getUser();

      // assert
      expect(result, isA<List<User>>());
      expect(result.length, 2);
      expect(result[0].id, 1);
      expect(result[0].firstName, 'John Doe');
      expect(result[1].id, 2);
      expect(result[1].firstName, 'Jane Doe');
    });
  });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 12:42:23