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

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 依赖),步骤如下:

  1. 在 pubspec.yaml 中添加依赖:
dev_dependencies:
  mockito: ^5.4.0
  build_runner: ^2.4.4
  1. 用 @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"
  });
}
  1. 运行命令生成 Mock 类:
flutter pub run build_runner build

这样生成的 Mock 类会自动处理非空类型的默认返回逻辑,你只需要在测试中 Stub 需要自定义返回值的方法即可,不需要手动重写任何方法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 02:25:25