You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为依赖上下文的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 12:45:18