Dart使用Mocktail编写单元测试遇类型不匹配错误求助
问题解决:Mock嵌套
logIn方法时出现Null类型转换错误 错误根源
你当前的测试代码直接使用MockLoginRepositoryImpl实例调用authenticate方法,但Mockito的Mock类会将所有方法默认返回null——包括你想要测试的authenticate本身,而非仅mock内部的logIn方法。这就导致authenticate执行到await logIn()时,实际调用的是mock的logIn方法(返回null),从而抛出类型转换错误。
解决方案:使用Mockito的Spy功能
Spy可以保留类的真实方法实现,仅mock指定的方法,完美适配你需要测试authenticate真实逻辑、同时mock内部logIn的场景。
修改后的完整测试代码
import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; class MockBuildContext extends Mock implements BuildContext {} class MockUtil extends Mock implements Util {} class MockLoginRepositoryImpl extends Mock implements LoginRepositoryImpl {} void main() { TestWidgetsFlutterBinding.ensureInitialized(); late LoginRepositoryImpl loginRepository; late BuildContext context; late Util util; late MockLoginRepositoryImpl mockLoginRepo; setUp(() { context = MockBuildContext(); util = MockUtil(); // 创建真实的Repository实例 loginRepository = LoginRepositoryImpl(); // 创建Mock实例用于Spy包装 mockLoginRepo = MockLoginRepositoryImpl(); // Spy包装:保留真实方法,仅mock指定方法 loginRepository = spy(loginRepository, mockLoginRepo); }); group('authenticate', () { test('authenticate method - valid userId and password', () async { // Arrange when(() => util.getDeviceId()) .thenAnswer((_) => Future.value('deviceId')); // 使用匹配器确保参数匹配:any()适配复杂类型BuildContext,eq匹配确定参数 when(() => loginRepository.logIn( context: any(), credentials: eq('password'), deviceId: eq('deviceId'), userId: eq('userId'), )).thenAnswer((_) => Future.value(UserPermissionApiResponse( result: true, message: 'Login successful', ))); // Act final response = await loginRepository.authenticate( 'userId', 'password', context, util, ); // Assert expect(response.result, true); expect(response.message, 'Login successful'); // 验证logIn方法是否按预期被调用 verify(loginRepository.logIn( context: any(), credentials: eq('password'), deviceId: eq('deviceId'), userId: eq('userId'), )).called(1); }); }); }
关键修改点说明
- 替换Mock为Spy:创建真实的
LoginRepositoryImpl实例,再用Spy包装,确保authenticate执行真实逻辑,仅logIn被mock。 - 参数匹配优化:对
BuildContext这类复杂类型使用any()匹配器,避免因对象相等性判断导致mock不触发;对确定参数(如密码、设备ID)使用eq()精确匹配。 - 增加方法调用验证:通过
verify()确认logIn方法按预期被调用一次,提升测试的可靠性。
内容的提问来源于stack exchange,提问作者divyanshu verma
相关产品推荐
相关产品推荐

