如何在Flutter中mock universal_html包完成方法调用的测试验证
实现方案
核心问题是universal_html暴露的html.window属于顶层全局对象,无法直接被Mockito拦截mock,需要先做解耦处理,具体操作如下:
步骤1:封装浏览器操作抽象层
把直接调用html.window.open()的逻辑抽成可注入的服务类,避免业务代码和universal_html的顶层对象强耦合:
import 'package:universal_html/html.dart' as html; // 定义抽象接口 abstract class BrowserWindowService { void open(String url, String target, {String? options}); } // 生产环境真实实现 class RealBrowserWindow implements BrowserWindowService { @override void open(String url, String target, {String? options}) { html.window.open(url, target, options); } }
业务代码中不再直接调用html.window.open,改为依赖注入BrowserWindowService实例:
class YourBusinessClass { final BrowserWindowService windowService; // 构造注入,生产环境传入RealBrowserWindow实例即可 const YourBusinessClass(this.windowService); void openTargetPage() { // 原有直接调用html.window.open的位置替换为服务类方法 windowService.open('https://target.com', '_blank', options: 'width=800,height=600'); } }
步骤2:生成Mock服务类
确保已在pubspec.yaml的dev_dependencies中引入mockito和build_runner,在测试文件中添加注解生成Mock实现:
import 'package:mockito/mockito.dart'; import 'package:mockito/annotations.dart'; // 导入你自己的业务文件 import 'your_business_file.dart'; // 执行dart run build_runner build命令后会自动生成对应mock文件 @GenerateMocks([BrowserWindowService]) import 'window_test.mocks.dart';
步骤3:编写测试验证调用逻辑
void main() { late MockBrowserWindowService mockWindowService; late YourBusinessClass businessLogic; setUp(() { mockWindowService = MockBrowserWindowService(); businessLogic = YourBusinessClass(mockWindowService); }); test('验证打开窗口方法调用参数符合预期', () { // 执行业务逻辑 businessLogic.openTargetPage(); // 验证open方法被调用1次,且传入参数匹配预期 verify(mockWindowService.open( 'https://target.com', '_blank', options: 'width=800,height=600', )).called(1); }); }
如果不想修改现有业务的注入逻辑,也可以用universal_html提供的全局window覆写能力:自行实现继承自html.Window的Mock类,在测试的setUp阶段赋值给html.window即可,不过该方案会污染全局测试环境,多用例并行时容易出现状态冲突,更推荐上面的依赖注入方案。
内容的提问来源于stack exchange,提问作者Rahul Dole
相关产品推荐
相关产品推荐

