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

Flutter单元测试用Path Provider和Hive时遇MissingPluginException问题

解决方案

问题根源

  1. MissingPluginException:单元测试跑在纯Dart环境里,没有Flutter原生平台的支持,getApplicationDocumentsDirectory依赖原生通道才能工作,所以调用直接失败。
  2. LateInitializationError:因为Hive初始化失败,setUp里的todoBox = await Hive.openBox<TodoItemMock>('todoBox')根本没执行,导致用late修饰的todoBox变量没被初始化。

修复步骤

1. 替换Hive初始化目录,摆脱原生插件依赖

把HiveConfig里的getApplicationDocumentsDirectory换成Dart标准库的临时目录,不用再依赖Flutter原生插件:

class HiveConfig {
  static start() async {
    // 测试环境直接用系统临时目录,不需要path_provider
    Directory dir = Directory.systemTemp;
    Hive.init(dir.path);
  }
}

要是想兼顾生产和测试环境,可以改成支持自定义目录的写法:

class HiveConfig {
  static start({Directory? customDir}) async {
    // 测试传临时目录,生产用默认的getApplicationDocumentsDirectory
    Directory dir = customDir ?? await getApplicationDocumentsDirectory();
    Hive.init(dir.path);
  }
}

// 测试的setUp里传入临时目录
setUp(() async {
  await HiveConfig.start(customDir: Directory.systemTemp);
  // ...其他初始化代码
});

2. 修正测试断言的写法

todoBox.get(0)是同步方法,不需要用completion;而且findsNothing是Widget测试的匹配器,这里应该用isNull:

test('Get no results from the Box', () {
  expect(todoBox.get(0), isNull);
});

3. 确保Mock类和适配器匹配(可选)

你的TodoItemAdapter是给TodoItem写的,但测试用的是TodoItemMock,如果Hive识别不了这个Mock类,要么给TodoItemMock写个适配器,要么直接用真实的TodoItem类测试(如果只是测Hive操作,Mock业务类其实没必要)。要是坚持用Mock,就加个适配器:

class TodoItemMockAdapter extends TypeAdapter<TodoItemMock> {
  @override
  final typeId = 0; // 和TodoItemAdapter的typeId保持一致,或者用不同的

  @override
  TodoItemMock read(BinaryReader reader) {
    // Mock类直接返回实例就行
    return TodoItemMock();
  }

  @override
  void write(BinaryWriter writer, TodoItemMock obj) {
    // Mock类不需要实际写入逻辑,空实现就行
  }
}

// 在setUp里注册这个适配器
setUp(() async {
  await HiveConfig.start(customDir: Directory.systemTemp);
  Hive.registerAdapter(TodoItemMockAdapter());
  todoBox = await Hive.openBox<TodoItemMock>('todoBox');
});

4. 让tearDownAll更安全

万一todoBox没初始化成功,关闭前先判断一下:

tearDownAll(() async {
  if (Hive.isBoxOpen('todoBox')) {
    await Hive.box('todoBox').close();
  }
  await Hive.close();
});

完整修复后的测试代码示例

import 'dart:io';

import 'package:flutter_test/flutter_test.dart';
import 'package:hive/hive.dart';
import 'package:mocktail/mocktail.dart';
import 'package:todo_app/src/modules/adapter/todo_adapter.dart';

late Box<TodoItemMock> todoBox;

class TodoItemMock extends Mock implements TodoItem {}

class TodoItemMockAdapter extends TypeAdapter<TodoItemMock> {
  @override
  final typeId = 0;

  @override
  TodoItemMock read(BinaryReader reader) => TodoItemMock();

  @override
  void write(BinaryWriter writer, TodoItemMock obj) {}
}

class HiveConfig {
  static start({Directory? customDir}) async {
    Directory dir = customDir ?? Directory.systemTemp;
    Hive.init(dir.path);
  }
}

void main() {
  setUp(() async {
    await HiveConfig.start(customDir: Directory.systemTemp);
    Hive.registerAdapter(TodoItemMockAdapter());
    todoBox = await Hive.openBox<TodoItemMock>('todoBox');
  });

  tearDownAll(() async {
    if (Hive.isBoxOpen('todoBox')) {
      await Hive.box('todoBox').close();
    }
    await Hive.close();
  });

  test('Get no results from the Box', () {
    expect(todoBox.get(0), isNull);
  });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 20:37:04