Flutter单元测试:Mockito模拟类方法重写的必要性及疑问
Flutter Mockito 单元测试疑问解答
你的示例代码
class User { final String name; User({required this.name}); } class UserService { User getUser() { return User(name: "sample user"); } String getUserName() { return "sample name"; } } class MockUserService extends Mock implements UserService { @override User getUser() { return super.noSuchMethod( Invocation.getter(#getUser), returnValue: User(name: 'Mock User'), ) as User; } @override String getUserName() { return super.noSuchMethod( Invocation.method(#getUserName,[]), returnValue: "mock name" ) ; } } void main(){ test('test mock', () { var mockUserService = MockUserService(); when(mockUserService.getUserName()).thenReturn("hello"); print("U " + mockUserService.getUserName()); }); }
疑问解答
1. 为什么不重写方法会报「type 'Null' is not a subtype of type 'String'」?
Mockito 的 Mock 类默认行为是:当调用未被 Stub的方法时,会返回 null。而你的 UserService 中,getUser() 返回非空的 User 类型,getUserName() 返回非空的 String 类型——在 Dart 空安全规则下,null 无法赋值给非空类型,因此直接调用未重写、未 Stub 的方法时会触发类型转换错误。
你手动重写方法的初衷可能是想给默认返回值,但这其实不是 Mockito 的标准用法,反而会引发后续问题。
2. 为什么重写方法定义的返回值不生效?
你在重写方法时调用了 super.noSuchMethod(),而 Mockito 的 Mock 类对 noSuchMethod 的实现逻辑是:优先使用通过 when(...).thenReturn(...) 配置的 Stub 返回值;如果没有 Stub,则默认返回 null——你传入的 returnValue 参数会被 Mockito 的内部逻辑忽略,所以即使写了默认返回值也不会生效。
另外,你完全不需要同时做「手动重写方法」和「Stub」,这是错误的使用方式。Mockito 的正确姿势是用代码生成来创建 Mock 类,而非手动继承并重写。
正确的使用方式
使用 Mockito 的代码生成功能(需要添加 build_runner 依赖),步骤如下:
- 在
pubspec.yaml中添加依赖:
dev_dependencies: mockito: ^5.4.0 build_runner: ^2.4.4
- 用
@GenerateMocks注解自动生成 Mock 类:
import 'package:mockito/mockito.dart'; import 'package:test/test.dart'; class User { final String name; User({required this.name}); } class UserService { User getUser() { return User(name: "sample user"); } String getUserName() { return "sample name"; } } // 自动生成 MockUserService @GenerateMocks([UserService]) void main(){ test('test mock', () { var mockUserService = MockUserService(); // Stub 需要自定义返回值的方法 when(mockUserService.getUserName()).thenReturn("hello"); when(mockUserService.getUser()).thenReturn(User(name: "Mock User")); print("U " + mockUserService.getUserName()); // 输出 "U hello" print(mockUserService.getUser().name); // 输出 "Mock User" }); }
- 运行命令生成 Mock 类:
flutter pub run build_runner build
这样生成的 Mock 类会自动处理非空类型的默认返回逻辑,你只需要在测试中 Stub 需要自定义返回值的方法即可,不需要手动重写任何方法。
内容的提问来源于stack exchange,提问作者SHA
相关产品推荐
相关产品推荐

