如何为依赖上下文的Flutter本地化工具类编写单元测试?
如何为依赖BuildContext的翻译工具类编写单元测试?
我有一个依赖BuildContext输出翻译结果的工具类,核心代码如下:
static String doSomeLogicAndTranslate(String firstArg, BuildContext context) { //... return AppLocalizations.of(context)!.someKey; }
现在想给这个类写单元测试,但卡在了BuildContext参数的处理上。
已尝试的方案
- 用Mockito模拟
BuildContext传入,但在localizations.dart的以下代码位置返回null:
static T? of<T>(BuildContext context, Type type) { final _LocalizationsScope? scope = context.dependOnInheritedWidgetOfExactType<_LocalizationsScope>(); /// Scope is null here return scope?.localizationsState.resourcesFor<T?>(type); }
找了不少资料,没找到能解决的办法,这个问题看似简单实际棘手。
可行解决方案
方案1:直接模拟AppLocalizations而非BuildContext
不用纠结模拟BuildContext,直接把工具类的逻辑和BuildContext解耦,新增一个依赖AppLocalizations的内部方法,对外保留原接口。这样单元测试时直接模拟AppLocalizations即可。
修改工具类:
// 内部方法,直接依赖AppLocalizations,方便测试 static String _doLogicAndTranslate(String firstArg, AppLocalizations loc) { //... 原来的业务逻辑 return loc.someKey; } // 对外接口不变,兼容原有调用 static String doSomeLogicAndTranslate(String firstArg, BuildContext context) { return _doLogicAndTranslate(firstArg, AppLocalizations.of(context)!); }
单元测试代码:
test('测试翻译逻辑正确性', () { // 模拟AppLocalizations实例 final mockLoc = MockAppLocalizations(); // 预设翻译字段的返回值 when(mockLoc.someKey).thenReturn('预期的翻译文本'); // 调用内部方法执行测试 final result = YourUtils._doLogicAndTranslate('测试参数', mockLoc); expect(result, '预期的翻译文本'); verify(mockLoc.someKey).called(1); });
方案2:用Widget测试环境提供真实BuildContext
如果必须依赖真实的BuildContext,可以用Flutter的Widget测试框架,构建一个包含Localizations组件的测试Widget,从中获取有效的上下文。
测试代码示例:
testWidgets('测试工具类翻译功能', (tester) async { await tester.pumpWidget( MaterialApp( localizationsDelegates: const [ AppLocalizations.delegate, // 按需添加其他本地化delegate ], supportedLocales: const [Locale('en')], home: Builder( builder: (context) { // 在这里调用工具类方法 final result = YourUtils.doSomeLogicAndTranslate('测试参数', context); expect(result, '对应的英文翻译内容'); return const SizedBox(); }, ), ), ); });
方案3:给BuildContext打桩返回LocalizationsScope(不推荐)
如果坚持用纯单元测试而非Widget测试,可以手动给BuildContext的dependOnInheritedWidgetOfExactType方法打桩,返回模拟的_LocalizationsScope。但注意_LocalizationsScope是Flutter内部私有类,后续版本更新可能导致代码失效。
示例代码:
test('模拟BuildContext获取Localizations', () { final mockContext = MockBuildContext(); final mockLoc = MockAppLocalizations(); // 模拟内部私有类实例 final mockScope = MockLocalizationsScope(); final mockState = MockLocalizationsState(); when(mockState.resourcesFor<AppLocalizations>(AppLocalizations)).thenReturn(mockLoc); when(mockScope.localizationsState).thenReturn(mockState); when(mockContext.dependOnInheritedWidgetOfExactType<_LocalizationsScope>()) .thenReturn(mockScope); when(mockLoc.someKey).thenReturn('预期文本'); final result = YourUtils.doSomeLogicAndTranslate('测试参数', mockContext); expect(result, '预期文本'); });
内容的提问来源于stack exchange,提问作者tomerpacific
相关产品推荐
相关产品推荐

