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

如何用Mockito测试Flutter中异步RSA密钥Provider代码?

解决Flutter测试中RSAProvider动态库加载失败问题

问题背景

在测试Flutter的RSAKeysProvider时,调用generate方法会触发动态库librsa_bridge.dylib加载失败的错误,无法验证公钥私钥是否不同。

待测试的RSAKeysProvider代码:

class RSAKeysProvider {
    KeyPair? _keyPair;

    KeyPair? get keyPair => _keyPair;
    set setKeyPair(KeyPair keyPair) => _keyPair = keyPair;

    Future<void> generate(String bits) async {
        var keyPair = await RSA.generate(int.parse(bits));
        _keyPair = keyPair;
        notifyListeners();
    }
}

当前测试代码(运行报错):

test('Public and private key should be different', () async {
      final MockRSAKeysProvider rsaKeys = MockRSAKeysProvider();

      when(rsaKeys.generate(any)).thenAnswer((value) async {
        KeyPair keyPair = await RSA.generate(2048);
        rsaKeys.setKeyPair = keyPair;
      });

      await rsaKeys.generate('2048');

      expect(rsaKeys.keyPair?.privateKey, isNotNull);
      expect(rsaKeys.keyPair?.publicKey, isNotNull);
    });

报错信息:

Invalid argument(s): Failed to load dynamic library 'librsa_bridge.dylib': dlopen(librsa_bridge.dylib, 0x0001): tried: 'librsa_bridge.dylib' (no such file), '/System/Volumes/Preboot/Cryptexes/OSlibrsa_bridge.dylib' (no such file), '/opt/homebrew/Caskroom/flutter/3.7.3/flutter/bin/cache/artifacts/engine/darwin-x64/./librsa_bridge.dylib' (no such file), '/opt/homebrew/Caskroom/flutter/3.7.3/flutter/bin/cache/artifacts/engine/darwin-x64/../../../librsa_bridge.dylib' (no such file), '/opt/homebrew/Caskroom/flutter/3.7.3/flutter/bin/cache/artifacts/engine/darwin-x64/Frameworks/librsa_bridge.dylib' (no such file), '/opt/homebrew/Caskroom/flutter/3.7.3/flutter/bin/cache/artifacts/engine/darwin-x64/./librsa_bridge.dylib' (no such file), '/opt/homebrew/Caskroom/flutter/3.7.3/flutter/bin/cache/artifacts/engine/darwin-x64/../../../librsa_bridge.dylib' (no such file), '/opt/homebrew/Caskroom/flutter/3.7.3/flutter/bin/cache/artifacts/engine/darwin-x64/Frameworks/librsa_bridge.dylib' (no such file), '/usr/lib/librsa_bridge.dylib' (no such file, not in dyld cache), 'librsa_bridge.dylib' (no such file), '/usr/lib/librsa_bridge.dylib' (no such file, not in dyld cache)
  dart:ffi                                     new DynamicLibrary.open
  package:fast_rsa/bridge/binding.dart 117:33  Binding.openLib
  package:fast_rsa/bridge/binding.dart 26:16   new Binding._internal
  package:fast_rsa/bridge/binding.dart 17:45   Binding._singleton
  package:fast_rsa/bridge/binding.dart         Binding._singleton
  package:fast_rsa/bridge/binding.dart 22:12   new Binding
  package:fast_rsa/fast_rsa.dart 40:32         RSA.bindingEnabled
  package:fast_rsa/fast_rsa.dart               RSA.bindingEnabled
  package:fast_rsa/fast_rsa.dart 43:9          RSA._call
  package:fast_rsa/fast_rsa.dart 79:22         RSA._keyPairResponse
  package:fast_rsa/fast_rsa.dart 437:18        RSA.generate
  test/rsa_keys.test.dart 32:37                main.<fn>.<fn>.<fn>
  package:mockito/src/mock.dart 185:45         Mock.noSuchMethod
  test/rsa_keys.test.mocks.dart 75:53          MockRSAKeysProvider.generate
  test/rsa_keys.test.dart 36:21                main.<fn>.<fn>

错误原因

测试中直接调用了RSA.generate,而fast_rsa库依赖的底层动态库在纯Dart测试环境(而非真机/模拟器)中无法加载——这类原生库通常需要在Flutter的宿主环境中才能正常运行。

解决方案

核心思路是Mock掉RSA.generate的调用,不依赖真实的原生库,而是构造模拟的KeyPair对象来测试RSAKeysProvider的逻辑:

  • 停止在测试中调用真实的RSA.generate
  • 构造模拟的KeyPair数据,确保Mock的RSAKeysProvider在调用generate后正确设置keyPair
  • 验证公钥和私钥的逻辑正确性

修改后的测试代码

import 'package:test/test.dart';
import 'package:mockito/mockito.dart';
import 'package:your_app_path/rsa_keys_provider.dart'; // 替换为实际文件路径

// 模拟KeyPair类,根据实际KeyPair结构调整字段
class MockKeyPair extends Mock implements KeyPair {
  @override
  final String publicKey = 'mock_public_key_123';
  @override
  final String privateKey = 'mock_private_key_456';
}

class MockRSAKeysProvider extends Mock implements RSAKeysProvider {
  KeyPair? _mockKeyPair;

  @override
  KeyPair? get keyPair => _mockKeyPair;

  @override
  set setKeyPair(KeyPair keyPair) => _mockKeyPair = keyPair;

  @override
  Future<void> generate(String bits) async {
    // 直接构造模拟KeyPair,跳过真实RSA生成逻辑
    _mockKeyPair = MockKeyPair();
    notifyListeners();
  }
}

void main() {
  test('Public and private key should be different', () async {
    final MockRSAKeysProvider rsaKeys = MockRSAKeysProvider();

    await rsaKeys.generate('2048');

    expect(rsaKeys.keyPair?.privateKey, isNotNull);
    expect(rsaKeys.keyPair?.publicKey, isNotNull);
    expect(rsaKeys.keyPair?.privateKey, isNot(equals(rsaKeys.keyPair?.publicKey)));
  });
}

也可以用Mockito的when语法实现:

test('Public and private key should be different', () async {
  final MockRSAKeysProvider rsaKeys = MockRSAKeysProvider();
  final mockKeyPair = MockKeyPair();

  when(rsaKeys.generate(any)).thenAnswer((_) async {
    rsaKeys.setKeyPair = mockKeyPair;
  });

  await rsaKeys.generate('2048');

  expect(rsaKeys.keyPair, equals(mockKeyPair));
  expect(rsaKeys.keyPair?.privateKey, isNot(equals(rsaKeys.keyPair?.publicKey)));
});

额外说明

如果需要测试RSA.generate的真实逻辑,应该使用集成测试(而非单元测试),在真机或模拟器环境中运行,这样才能正确加载原生动态库。单元测试的核心是验证自身业务逻辑,而非第三方库的实现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 08:59:21