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
相关产品推荐
相关产品推荐

