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

Dart项目测试中Mock Stdin遇final属性赋值错误求助

Dart测试中模拟Stdin的问题解决

问题场景

在编写Dart项目测试用例时,尝试模拟终端输入替换全局stdin时遇到错误,测试代码及报错如下:

测试代码

test(
        'lerStringComTexto should print the given text and read a string from stdin',
        () async {
      final input = 'hello world';
      final expected = input;
      final mockStdin = Stream<List<int>>.fromIterable([utf8.encode(input)]);
      stdin = mockStdin.asBroadcastStream();

      final result = await ConsoleUtils.lerStringComTexto('Enter a string: ');

      expect(result, equals(expected));
    }); 

报错信息

'stdin' can't be used as a setter because it's final.
Try finding a different setter, or making 'stdin' non-final.dartassignment_to_final

解决方法

全局dart.io.stdin是final变量,无法直接赋值替换,推荐通过依赖注入的方式让代码支持自定义输入源,具体步骤如下:

1. 修改工具类方法,添加可选Stdin参数

调整ConsoleUtils的lerStringComTexto方法,增加一个可选的Stdin参数,默认使用系统全局的stdin:

import 'dart:io' as io;
import 'dart:convert';

class ConsoleUtils {
  static Future<String> lerStringComTexto(String prompt, {io.Stdin? inputSource}) async {
    // 使用传入的输入源,默认用系统stdin
    final stdin = inputSource ?? io.stdin;
    print(prompt);
    // 读取输入并解码为字符串
    final inputBytes = await stdin.first;
    return utf8.decode(inputBytes).trim();
  }
}

2. 编写测试用例,传入模拟的Stdin

可以手动实现模拟类或使用mockito库来创建Stdin的Mock实例,这里以mockito为例:

步骤1:添加依赖

在pubspec.yaml的dev_dependencies中添加:

dev_dependencies:
  mockito: ^5.4.0
  build_runner: ^2.4.4

步骤2:生成Mock类

创建mock_stdins.dart文件:

import 'package:mockito/mockito.dart';
import 'dart:io';

class MockStdin extends Mock implements Stdin {}

然后运行命令生成Mock代码:

dart run build_runner build

步骤3:编写测试

import 'package:test/test.dart';
import 'package:mockito/mockito.dart';
import 'dart:convert';
import 'package:your_project_name/console_utils.dart';
import 'mock_stdins.dart';

void main() {
  test(
    'lerStringComTexto should return input string after printing prompt',
    () async {
      final input = 'hello world';
      final expected = input.trim();
      final mockStdin = MockStdin();

      // 配置Mock的行为:当读取first时返回编码后的输入
      when(mockStdin.first).thenAnswer((_) async => utf8.encode(input));

      // 调用方法时传入Mock的Stdin
      final result = await ConsoleUtils.lerStringComTexto('Enter a string: ', inputSource: mockStdin);

      // 验证结果和行为
      expect(result, equals(expected));
      verify(print('Enter a string: ')).called(1);
    },
  );
}

替代方案:手动模拟Stdin

如果不想使用第三方库,也可以手动实现一个模拟的Stdin类:

import 'dart:async';
import 'dart:io';
import 'dart:convert';

class MockStdin extends Stdin {
  final Stream<List<int>> _inputStream;

  MockStdin(List<int> inputBytes) : _inputStream = Stream.value(inputBytes);

  @override
  Future<List<int>> get first => _inputStream.first;
  
  // 其他Stdin的抽象方法按需实现,测试未用到的可留空
  @override
  bool get echoMode => throw UnimplementedError();
  @override
  set echoMode(bool value) => throw UnimplementedError();
  @override
  bool get lineMode => throw UnimplementedError();
  @override
  set lineMode(bool value) => throw UnimplementedError();
}

测试时直接实例化这个类传入即可。

内容的提问来源于stack exchange,提问作者Guido Aguiar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 15:25:57