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

Flutter单元测试报错:Expected<false> Actual<Closure: ()=>Future<bool>>如何修复?

AuthService.authorize方法单元测试错误修复

问题背景

我正在为AuthService类中的authorize异步方法编写单元测试,该方法代码如下:

Future<bool> authorize() async {
  AuthorizationTokenResponse? authResult;

  try {
    authResult = await appAuth.authorizeAndExchangeCode(
      AuthorizationTokenRequest(
          bsEnv.AD_CLIENT_ID!,
         ));

    if (authResult != null) {
      return true;
    }
  } on PlatformException catch (e) {
      forgetPassword();
    }
  }

  return false;
}

使用Mocktail创建Mock对象编写的测试代码如下:

class MockBEnv extends Mock implements BEnv {}

class MockSharedPrefsService extends Mock implements SharedPrefsService {}

class MockFlutterAppAuth extends Mock implements FlutterAppAuth {}

class MockAuthorizationServiceConfiguration extends Mock
    implements AuthorizationServiceConfiguration {}

class MockAuthorizationTokenResponse extends Mock
    implements AuthorizationTokenResponse {}

class MockAuthorizationTokenRequest extends Mock
    implements AuthorizationTokenRequest {}

class MockTokenResponse extends Mock implements TokenResponse{}

class MockTokenRequest extends Mock implements TokenRequest{

}

void main() {
  late AuthService authService;
  late MockFlutterAppAuth mockFlutterAppAuth;
  late MockBEnv mockBEnv;
  late MockSharedPrefsService mockStorageService;
  late MockAuthorizationTokenResponse mockAuthorizationTokenResponse;
  late MockAuthorizationTokenRequest mockAuthorizationTokenRequest;
  
  const tUrl = 'https://endpoint/';
  const tUserImp = 'user';
  const tAppLan = 'sv-SE';
  const tClientId = 'client';
  const tIosUri = 'ios';
  const tTokenEndPoint = 'abcdeff';

  setUp(() {
    mockFlutterAppAuth = MockFlutterAppAuth();
    mockBEnv = MockBEnv();
    mockStorageService = MockSharedPrefsService();
    mockAuthorizationTokenRequest = MockAuthorizationTokenRequest();
    mockAuthorizationTokenResponse = MockAuthorizationTokenResponse();
    authService = AuthService(
        appAuth: mockFlutterAppAuth,
        bsEnv: mockBEnv,
        sharedPrefs: mockStorageService);
  });

  group('authorize', () {
    test(
        'should return true when the call to authorized method if result is not null',
        () async {
      // Arrange
      when(() => mockBEnv.AD_CLIENT_ID).thenAnswer((_) => tClientId);
      when(() => mockFlutterAppAuth
              .authorizeAndExchangeCode(mockAuthorizationTokenRequest))
          .thenAnswer((_)=> Future.value(mockAuthorizationTokenResponse));
      // Act
      final result =  authService.authorize;
      // Assert
      expect(() => result(), equals(false));
    });
  });
}

执行测试时出现错误:Expected: <false>,Actual: <Closure: () => Future<bool>>


错误原因与修复步骤

1. 未正确调用异步方法

原测试中final result = authService.authorize;只是获取了方法的引用,没有执行该方法,且异步方法必须通过await来获取最终的布尔结果。

2. Mock请求对象不匹配

原测试中Mock的是mockAuthorizationTokenRequest实例,但实际代码里是新建了一个AuthorizationTokenRequest对象,Mocktail默认采用严格匹配,导致Mock的方法不会被触发。

3. 断言逻辑与测试预期矛盾

测试用例描述是“当授权调用返回非null结果时返回true”,但断言却期望返回false,逻辑完全相反。


修复后的测试代码

group('authorize', () {
  test('should return true when authorization call returns non-null result', () async {
    // Arrange
    when(() => mockBEnv.AD_CLIENT_ID).thenReturn(tClientId);
    // 用any()匹配任意AuthorizationTokenRequest实例,也可以用argThat做精确匹配
    when(() => mockFlutterAppAuth.authorizeAndExchangeCode(any()))
        .thenAnswer((_) => Future.value(mockAuthorizationTokenResponse));
    
    // Act
    final result = await authService.authorize(); // 调用方法并await获取异步结果
    
    // Assert
    expect(result, equals(true)); // 匹配测试预期的true
    // 验证Mock方法确实被调用过一次
    verify(() => mockFlutterAppAuth.authorizeAndExchangeCode(any())).called(1);
  });
});

可选:精确匹配请求对象

如果需要验证传入的AuthorizationTokenRequest的属性是否正确,可以用argThat做精确匹配:

when(() => mockFlutterAppAuth.authorizeAndExchangeCode(
  argThat((request) => request.clientId == tClientId)
)).thenAnswer((_) => Future.value(mockAuthorizationTokenResponse));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 11:46:03