Flutter Web单元测试中window.open()返回null的问题排查
解决Flutter Web单元测试中
window.open返回null的问题 我明白你遇到的困扰——代码在真实浏览器里工作正常,但单元测试里因为window.open返回null而失败。这其实是测试环境和真实浏览器环境的差异导致的:测试用的Chrome实例会默认阻止弹窗,并且不会返回真实的窗口对象,所以open方法返回null,但这并不代表你的代码逻辑有问题。
下面是具体的解决方案,帮你调整测试逻辑,让测试能正确验证功能:
1. 重构代码,方便依赖注入
首先,我们可以稍微修改PrintReports的launchURL方法,让它可以接受一个可选的Window参数,这样测试时我们可以传入模拟对象,而不是直接依赖全局的html.window:
import 'package:flutter_web/material.dart'; import 'dart:html' as html; // ... 其他代码不变 class PrintReports extends StatelessWidget { const PrintReports({Key key}) : super(key: key); @override Widget build(BuildContext context) { return Column( children: [ RaisedButton( child: const Text("Print A Form . . ."), color: Colors.blue, onPressed: () => { // 这里调用时可以不传window参数,默认用全局的html.window launchURL("your-real-url-here"), }, ), ], ); } // 添加可选的window参数,用于测试注入mock Future<void> launchURL(String download_url, {html.Window? window}) async { try { // 使用传入的window或者全局的html.window final targetWindow = window ?? html.window; targetWindow.open(download_url, "Get_Submission"); } catch (e) { print(e); } } }
2. 使用Mock模拟Window对象,验证调用行为
我们不需要测试浏览器的window.open本身(那是浏览器的功能),我们需要测试的是我们的代码是否正确调用了window.open,并且传入了正确的参数。这里可以用mockito包来模拟Window对象:
第一步:添加依赖
在pubspec.yaml的dev_dependencies里添加mockito:
dev_dependencies: test: any mockito: ^5.4.0 # 用最新版本即可
第二步:编写测试代码
import 'dart:html' as html; import 'package:flutter_tests/main.dart'; import 'package:mockito/mockito.dart'; import 'package:test/test.dart'; // 创建Mock类模拟html.Window class MockWindow extends Mock implements html.Window {} void main(){ test("launchURL calls window.open with correct URL and window name", () async { // Arrange:准备测试环境和mock对象 final mockWindow = MockWindow(); final printReports = PrintReports(); const testUrl = "https://someurl.com/download"; const expectedWindowName = "Get_Submission"; // Act:调用要测试的方法 await printReports.launchURL(testUrl, window: mockWindow); // Assert:验证mock对象的open方法是否被正确调用 verify(mockWindow.open(testUrl, expectedWindowName)).called(1); }); }
为什么原来的测试会失败?
在测试用的Chrome实例中,浏览器会自动阻止弹窗,并且不会返回真实的WindowBase对象,所以window.open返回null。但这是测试环境的限制,不是你的代码问题——真实用户使用时,只要允许弹窗,这个方法就能正常工作。
我们的测试思路应该从验证返回值转换为验证行为是否正确:确认我们的代码确实调用了window.open,并且传入了正确的URL和窗口名称,这就足够证明功能逻辑是正确的。
运行修改后的测试,应该就能顺利通过了!
内容的提问来源于stack exchange,提问作者skillit zimberg
相关产品推荐
相关产品推荐

