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

