Flutter中测试Dart库Random方法:种子与Mock问题求解
问题:Flutter中测试Random方法的困境
我在Flutter里测试Dart的Random方法时遇到了麻烦:
- 用带种子的Random测试时,生成的序列固定,没法模拟无种子时的纯随机行为
- 尝试Mock Random方法,但因为代码里每次都是直接新建
Random()实例,没有通过依赖注入传入,导致Mock的方法根本不会被调用
以下是我尝试的代码:
bacground_color.dart
///Method responsible for change of colour of background. Color? colorChanger() { const parameterRandom = 100; const parameterNextInt = 256; int parameterARGB = 0; final parameterARGB2 = Random().nextInt(parameterNextInt); final parameterARGB3 = Random().nextInt(parameterNextInt); final parameterARGB4 = Random().nextInt(parameterNextInt); if (background == Color.fromARGB( parameterARGB, parameterARGB, parameterARGB, parameterARGB, )) //Case created done for the widget testing so that 1st time the color is, // what is specified in widget test and the second time it is all random { background = Color.fromARGB( Random(parameterRandom).nextInt(parameterNextInt), Random(parameterRandom).nextInt(parameterNextInt), Random(parameterRandom).nextInt(parameterNextInt), Random(parameterRandom).nextInt(parameterNextInt), ); } else { parameterARGB = Random().nextInt(parameterNextInt); background = Color.fromARGB( parameterARGB, parameterARGB2, parameterARGB3, parameterARGB4, ); } return background; }
main_file_unit_test.dart
import 'dart:math'; import 'dart:ui'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:solid_software/Model/background_color.dart'; class MockRandom extends Mock implements Random {} void main() { late MockRandom mockRandom; setUp(() { mockRandom = MockRandom(); }); test("Unit test of main method", () { const int nextIntParameter = 256; const int aRGBParameter = 74; when(() => mockRandom.nextInt(nextIntParameter)).thenReturn(aRGBParameter); final BackgroundColor backgroundColor = BackgroundColor(); expect(backgroundColor.background, const Color.fromARGB(0, 0, 0, 0)); backgroundColor.colorChanger(); expect( backgroundColor.background, const Color.fromARGB( aRGBParameter, aRGBParameter, aRGBParameter, aRGBParameter), ); }); }
解决方案:通过依赖注入实现可测试性
核心问题是代码中直接硬创建Random()实例,导致无法替换为Mock对象。解决思路是将Random作为依赖注入到BackgroundColor类中,这样测试时可以传入Mock实例,生产环境则使用默认的无种子Random。
步骤1:修改BackgroundColor类,添加依赖注入
import 'dart:math'; import 'dart:ui'; class BackgroundColor { Color background = const Color.fromARGB(0, 0, 0, 0); final Random _random; // 构造函数:允许传入自定义Random,默认使用无种子的Random实例 BackgroundColor([Random? random]) : _random = random ?? Random(); Color? colorChanger() { const parameterRandom = 100; const parameterNextInt = 256; int parameterARGB = 0; // 统一使用类内的_random实例,不再每次新建 final parameterARGB2 = _random.nextInt(parameterNextInt); final parameterARGB3 = _random.nextInt(parameterNextInt); final parameterARGB4 = _random.nextInt(parameterNextInt); if (background == const Color.fromARGB(0, 0, 0, 0)) { // 保持原有带种子的逻辑,这里单独创建带种子的Random final seededRandom = Random(parameterRandom); background = Color.fromARGB( seededRandom.nextInt(parameterNextInt), seededRandom.nextInt(parameterNextInt), seededRandom.nextInt(parameterNextInt), seededRandom.nextInt(parameterNextInt), ); } else { parameterARGB = _random.nextInt(parameterNextInt); background = Color.fromARGB( parameterARGB, parameterARGB2, parameterARGB3, parameterARGB4, ); } return background; } }
步骤2:修改测试代码,传入MockRandom实例
现在可以通过构造函数传入MockRandom,控制随机值的返回,实现精准测试:
import 'dart:math'; import 'dart:ui'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:solid_software/Model/background_color.dart'; class MockRandom extends Mock implements Random {} void main() { late MockRandom mockRandom; setUp(() { mockRandom = MockRandom(); }); test("第一次调用colorChanger生成带种子的随机颜色", () { const parameterNextInt = 256; // 预计算带种子Random(100)的输出值,保证测试一致性 final seededRandom = Random(100); final a = seededRandom.nextInt(parameterNextInt); final r = seededRandom.nextInt(parameterNextInt); final g = seededRandom.nextInt(parameterNextInt); final b = seededRandom.nextInt(parameterNextInt); final backgroundColor = BackgroundColor(); expect(backgroundColor.background, const Color.fromARGB(0, 0, 0, 0)); backgroundColor.colorChanger(); expect(backgroundColor.background, Color.fromARGB(a, r, g, b)); }); test("第二次调用colorChanger使用Mock生成指定颜色", () { const parameterNextInt = 256; // 定义Mock要返回的随机值 const argbVal = 74; const argb2Val = 100; const argb3Val = 150; const argb4Val = 200; // 按调用顺序设置返回值 when(() => mockRandom.nextInt(parameterNextInt)) .thenReturn(argb2Val) .thenReturn(argb3Val) .thenReturn(argb4Val) .thenReturn(argbVal); final backgroundColor = BackgroundColor(mockRandom); // 设置背景为非初始值,触发else分支 backgroundColor.background = const Color.fromARGB(1, 1, 1, 1); backgroundColor.colorChanger(); expect( backgroundColor.background, const Color.fromARGB(argbVal, argb2Val, argb3Val, argb4Val), ); // 验证Mock方法被调用了4次 verify(() => mockRandom.nextInt(parameterNextInt)).called(4); }); }
内容的提问来源于stack exchange,提问作者Aayush Sahay
相关产品推荐
相关产品推荐

