Firekart测试策略完全指南:用mockito编写UseCase与ViewModel单元测试
【免费下载链接】firekartAn Ecommerce application built in Flutter using Nodejs and MySQl.项目地址: https://gitcode.com/gh_mirrors/fi/firekart
Firekart 是一款用 Flutter + Node.js + MySQL 构建的开源电商应用,它内置了一套面向新手的完整测试策略:通过 mockito 为 UseCase 和 ViewModel 编写单元测试,让业务逻辑无需连接真实数据库即可验证。本指南带你快速掌握这套测试写法。
为什么选择 Firekart 学习 Flutter 单元测试
Firekart 采用经典的 Clean Architecture 分层(data、domain、presentation三大模块,见 modules/ 目录),每一层都有独立的test目录:
| 测试层 | 测试什么 | 测试位置 |
|---|---|---|
| UseCase 测试 | 领域层业务逻辑 | modules/domain/test/usecase/ |
| ViewModel 测试 | 界面状态与交互逻辑 | modules/presentation/test/features/ |
| Repository 测试 | 数据源聚合 | modules/data/test/repository/ |
这种"分层隔离"正是 Firekart 测试策略的核心:mock 掉依赖,只测当前层的逻辑。先克隆项目:
git clone https://gitcode.com/gh_mirrors/fi/firekart第一步:用 mockito 一键生成 Repository 桩
在 modules/domain/test/usecase/usecase_test.dart 中,作者用一行注解让 build_runner 自动生成全部 Repository 的 Mock 类:
@GenerateMocks([ AuthRepository, CartRepository, OrderRepository, ProductRepository, UserRepository, ])然后执行生成(由 melos 统一调度,见 melos.yaml 中的generateAll脚本):
melos generateAll会生成 modules/domain/test/usecase/usecase_test.mocks.dart,其中包含MockCartRepository等可直接注入的桩类。依赖声明在 modules/domain/pubspec.yaml 的dev_dependencies中:mockito ^5.4.1+build_runner ^2.4.4。
同一文件还集中定义了 mock 数据(mockCart、mockOrder、mockProduct等),所有 UseCase 测试共享,避免重复造数据。
编写 UseCase 单元测试的三个套路
以 modules/domain/test/usecase/get_cart_status_usecase_test.dart 为例,每个用例都遵循同一套Arrange → Act → Assert套路:
- Arrange:
when()给桩方法指定返回值。Firekart 用 dartz 的Either表达成功/失败:when(cartRepository.getCarts()) .thenAnswer((_) => Future.value(right(cart))); - Act:执行被测方法
await getCartStatusUseCase.execute()。 - Assert:双保险——
verify(...).called(1)确认 Repository 方法被正确调用;expect(result, Right(cart))确认返回值符合预期。
失败分支则返回left(NetworkError('', 402)),断言result.isLeft()。这种"成功 + 失败"成对编写的模式覆盖了 modules/domain/test/usecase/ 下 10 余个用例,包括加地址、加购、删除购物车商品等场景(如 modules/domain/test/usecase/add_address_usecase_test.dart)。
ViewModel 单元测试:验证按钮状态与登录流程
ViewModel 测试位于 presentation 层,思路是把 Repository 换成桩再注入 ViewModel。以 modules/presentation/test/features/otp_login/view_model/otp_login_viewmodel_test.dart.dart 为例:
- 按钮启用逻辑:输入 4 位验证码后
state.isButtonEnabled应为true,3 位则false——纯状态断言,无需 UI; - 发送验证码:
when(mockAuthRepository.login(...)).thenAnswer(...)后调用sendOtp(),用verify确认仓库方法只被调用一次; - OTP 校验:mock
verifyOtp返回Right(EmptyEntity(...)),断言加载状态复位。
同目录下 modules/presentation/test/features/phone_login/view_model/phone_login_viewmodel_test.dart 更轻量——直接 new 出 ViewModel,验证 10 位手机号才允许点击登录按钮。
一键运行全部测试:melos 工作流
Firekart 是 melos monorepo,在 melos.yaml 中定义了统一测试脚本,在仓库根目录执行即可对全部模块跑测试:
melos test其本质是:
melos exec -c 1 --dir-exists="test" --fail-fast \ -- flutter test --no-pub --dart-define=isRunningInTest=true--fail-fast让首个失败即停止,isRunningInTest则用于隔离 Firebase 等第三方服务——测试中不会出现真实网络调用。若想生成覆盖率报告,可改用melos testCov。
新手常见错误清单 ⚠️
- 忘记执行 build_runner:改了
@GenerateMocks列表却没跑melos generateAll,会报 Mock 类不存在; - 只测成功分支:Firekart 的惯例是成功/失败成对编写,遗漏
Left分支会漏掉错误处理回归; - 测试中连真实依赖:务必像示例那样注入
MockAuthRepository,而不是走依赖注入容器获取真实实例; - 断言不具体:
expect(result, Right(cart))优于只判断isRight(),能定位数据错误。
总结
Firekart 的测试策略可以浓缩为一句话:用 mockito 生成桩,用 dartz 的 Either 断言成败,用 melos 一键执行。跟着 modules/domain/test/usecase/ 和 modules/presentation/test/ 的现成用例模仿练习,你就能为自己的 Flutter 项目搭出一套干净的单元测试体系。
【免费下载链接】firekartAn Ecommerce application built in Flutter using Nodejs and MySQl.项目地址: https://gitcode.com/gh_mirrors/fi/firekart
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考