Flutter项目中如何开展Object Box单元测试?含CRUD操作测试及独立测试Store咨询
在Flutter中为Object Box编写单元测试(含CRUD全流程)
嘿,我来帮你搞定Flutter里Object Box的单元测试问题!首先明确告诉你:完全可以创建独立的测试用Object Box Store,而且这是单元测试的最佳实践——既能避免污染生产环境的数据库,又能保证每个测试用例的独立性,不会互相干扰。
一、先搞定测试专用的Store创建
要实现测试隔离,核心是创建一个仅在测试阶段运行的临时Store。Object Box支持两种方式:
- 内存模式:数据只存在于内存中,测试结束后自动销毁(推荐)
- 临时磁盘目录:数据写到临时文件夹,测试后手动删除
这里推荐用内存模式,代码实现非常简单:
import 'package:objectbox/objectbox.dart'; import 'package:test/test.dart'; import 'package:your_app/models/shape_model.dart'; import 'package:your_app/repos/shape_repo.dart'; Store? testStore; Box<ShapeModel>? testBox; void main() { // 每个测试用例运行前初始化测试Store和Box setUp(() async { // directory设为null,开启内存模式 testStore = await Store.open(getObjectBoxModel(), directory: null); testBox = testStore!.box<ShapeModel>(); }); // 每个测试用例结束后关闭Store,释放资源 tearDown(() { testStore?.close(); }); // 接下来编写具体测试用例 }
二、针对CRUD操作的单元测试示例
首先要优化你的ShapeRepo类——为了方便测试,建议给它加一个可选的Box参数,支持依赖注入,这样测试时可以传入我们的测试Box:
class ShapeRepo { final Box<ShapeModel> _box; // 生产环境默认用全局store的box,测试时可以传入自定义box ShapeRepo({Box<ShapeModel>? box}) : _box = box ?? store.box<ShapeModel>(); void saveShape(ShapeModel model) { _box.put(model); } // 假设还有这些CRUD方法 List<ShapeModel> getAllShapes() => _box.getAll(); void updateShape(ShapeModel model) => _box.put(model); void deleteShape(int id) => _box.remove(id); }
现在针对每个CRUD操作写测试:
1. 创建(Create)测试
验证saveShape方法能否正确插入数据:
test('saveShape should successfully insert a ShapeModel', () { final repo = ShapeRepo(box: testBox); final testShape = ShapeModel(id: 1, name: 'Circle', color: 'Red'); repo.saveShape(testShape); final savedShape = testBox!.get(1); expect(savedShape, isNotNull); expect(savedShape!.name, 'Circle'); expect(savedShape.color, 'Red'); });
2. 读取(Read)测试
验证getAllShapes能否返回所有已保存的数据:
test('getAllShapes should return all saved ShapeModels', () { final repo = ShapeRepo(box: testBox); // 先插入测试数据 final shapes = [ ShapeModel(id: 1, name: 'Square', color: 'Blue'), ShapeModel(id: 2, name: 'Triangle', color: 'Green') ]; testBox!.putMany(shapes); final result = repo.getAllShapes(); expect(result.length, 2); expect(result.any((s) => s.name == 'Square'), isTrue); expect(result.any((s) => s.name == 'Triangle'), isTrue); });
3. 更新(Update)测试
验证updateShape能否修改已存在的数据:
test('updateShape should modify an existing ShapeModel', () { final repo = ShapeRepo(box: testBox); // 先插入原始数据 final originalShape = ShapeModel(id: 1, name: 'Circle', color: 'Red'); testBox!.put(originalShape); // 更新颜色 final updatedShape = ShapeModel(id: 1, name: 'Circle', color: 'Blue'); repo.updateShape(updatedShape); final savedShape = testBox!.get(1); expect(savedShape!.color, 'Blue'); expect(savedShape.name, 'Circle'); // 验证未修改的字段保持不变 });
4. 删除(Delete)测试
验证deleteShape能否删除指定数据:
test('deleteShape should remove the specified ShapeModel', () { final repo = ShapeRepo(box: testBox); final testShape = ShapeModel(id: 1, name: 'Circle', color: 'Red'); testBox!.put(testShape); repo.deleteShape(1); final deletedShape = testBox!.get(1); expect(deletedShape, isNull); });
三、关键注意事项
- 依赖注入是核心:一定要让你的Repo类支持传入Box实例,不要硬编码依赖全局Store,这是实现可测试性的关键。
- 内存模式效率高:用
directory: null创建的内存Store,测试数据不会落地到磁盘,测试结束后自动销毁,无需手动清理。 - 测试隔离要保证:每个测试用例都会重新初始化Store,所以测试之间不会互相干扰,结果更可靠。
- 模型文件要同步:如果测试时遇到模型相关的错误,先运行
flutter pub run build_runner build重新生成Object Box的模型文件。
内容的提问来源于stack exchange,提问作者raphire
相关产品推荐
相关产品推荐

