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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 17:22:08