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

Flutter报错:type 'Null'非Future<bool>子类型的测试问题排查

解决SharedPreferences Todo测试中“type 'Null' is not a subtype of type 'Future'”错误

问题原因

这个错误核心是Mockito的Mock方法未匹配到实际调用,默认返回null,但SharedPreferences.setString要求返回Future<bool>,类型不匹配触发报错。常见触发场景:

  • 测试用的键名常量和业务代码里硬编码的键名不一致(比如测试用prefKey,业务代码用'SAVED_TODOS')
  • Mock的SharedPreferences实例未正确初始化或注入到数据源类

解决方案

1. 统一键名常量

业务代码和测试代码必须用完全一致的键名,避免Mock匹配失败:

  • 定义全局常量:
    const String kSavedTodosKey = 'SAVED_TODOS';
    
  • 修改业务代码:
    @override
    Future<void> localTodos(List<TodoModel> todos) async {
      final List<Map<String, dynamic>> todoList = todos.map((todo) => todo.toJson()).toList();
      await sharedPreferences.setString(kSavedTodosKey, json.encode(todoList));
    }
    
    @override
    Future<List<TodoModel>> getLocalTodos() async {
      final jsonString = sharedPreferences.getString(kSavedTodosKey);
      if (jsonString != null) {
        List decodedJson = json.decode(jsonString);
        return decodedJson.map<TodoModel>((json) => TodoModel.fromJson(json)).toList();
      } else {
        throw Exception('No saved todos found');
      }
    }
    
  • 修改测试代码:
    test('should call SharedPreferences to save the data', () async {
      final expectedJsonString = json.encode(todos.map((todo) => todo.toJson()).toList());
    
      when(mockSharedPreferences.setString(kSavedTodosKey, expectedJsonString))
          .thenAnswer((_) async => true);
    
      await localDataSource.localTodos(todos);
    
      verify(mockSharedPreferences.setString(kSavedTodosKey, expectedJsonString)).called(1);
    });
    

2. 确认Mock初始化正确

确保mockSharedPreferences是Mockito的Mock类实例,且已正确注入到数据源:

import 'package:mockito/mockito.dart';
import 'package:shared_preferences/shared_preferences.dart';

class MockSharedPreferences extends Mock implements SharedPreferences {}

void main() {
  late LocalDataSource localDataSource;
  late MockSharedPreferences mockSharedPreferences;

  setUp(() {
    mockSharedPreferences = MockSharedPreferences();
    // 假设你的数据源类是LocalDataSourceImpl,构造函数接收SharedPreferences
    localDataSource = LocalDataSourceImpl(sharedPreferences: mockSharedPreferences);
  });

  // 你的测试组...
}

3. 兜底Mock所有setString调用(可选)

如果需要兼容多个键名,添加通用Mock避免未匹配的调用返回null:

when(mockSharedPreferences.setString(any, any)).thenAnswer((_) async => true);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 19:42:39