【问题标题】:type 'Null' is not a subtype of type 'Future<Response>' when testing mocked http client with Mocktail使用 Mocktail 测试模拟 http 客户端时,类型“Null”不是“Future<Response>”类型的子类型
【发布时间】:2021-08-26 03:47:30
【问题描述】:

我编写了一个简单的 HTTP get 测试,使用 Mocktail 来模拟 HTTP 客户端。当我在测试中调用 get 方法时,我收到“'Null' 类型不是'Future' 类型的子类型”。

有人知道为什么会这样吗?

这是测试:

class MockHttpClient extends Mock implements http.Client {}

void main() {
  late IdRemoteDataSourceImpl dataSource;
  late MockHttpClient mockHttpClient;

  setUp(
    () {
      mockHttpClient = MockHttpClient();
      dataSource = IdRemoteDataSourceImpl(client: mockHttpClient);
    },
  );

  group('Get id', () {
    test(
      'when response code is 200',
      () async {
        final url = Uri.parse('https://api.test.com/');
        const tUsername = 'username';
        final accountJson = json.decode(
          fixture('account.json'),
          // ignore: avoid_as
        ) as Map<String, dynamic>;
        final tIdModel = IdModel.fromJson(accountJson);
        // arrange
        when(() => mockHttpClient.get(url))
            .thenAnswer((_) async => http.Response(
                  fixture('account.json'),
                  200,
                ));
        // act
        final testResult = await dataSource.getId(tUsername);
        // assert
        // expect(testResult, tIdModel);
      },
    );
  });
}

以下行运行时发生错误:

final testResult = await dataSource.getId(tUsername);

正在测试的代码:

import 'dart:convert';

import 'package:http/http.dart' as http;

class IdModel {
  IdModel({required this.id});

  final String id;

  factory IdModel.fromJson(Map<String, dynamic> json) {
    return IdModel(id: json['id'].toString());
  }
}

abstract class IdRemoteDataSource {
  Future<IdModel> getId(String username);
}

class IdRemoteDataSourceImpl implements IdRemoteDataSource {
  IdRemoteDataSourceImpl({required this.client});

  final http.Client client;

  @override
  Future<IdModel> getId(String username) async {
    final url = Uri.parse('https://api.test.com/query?username=$username');
    final response = await client.get(url);
    // ignore: avoid_as
    final responseJson = json.decode(response.body) as Map<String, dynamic>;
    return IdModel.fromJson(responseJson);
  }
}

【问题讨论】:

    标签: flutter dart mocking


    【解决方案1】:

    错误type 'Null' is not a subtype of type 'Future'... 发生在您调用尚未为模拟对象实现的方法或传递给它的参数不同时。

    在您的代码中,您将不同的 url 参数传递给 get(...) 方法。 Http客户端mock等待'https://api.test.com/'但实际上'https://api.test.com/query?username=$username'已经通过了。

    你有两种选择来解决它。

    1. 将相同的 url 从 when(...) 传递给将在测试期间传递的模拟方法:
    const tUsername = 'username';
    final url = Uri.parse('https://api.test.com/query?username=$tUsername');
    ...
    // arrange
    when(() => mockHttpClient.get(url))
      .thenAnswer((_) async => http.Response(
          fixture('account.json'),
          200,
      ),
    );
    
    
    1. 使用any匹配器(如果你不关心传递了哪个参数):
    registerFallbackValue(Uri.parse(''));
    ...
    when(() => mockHttpClient.get(any()))
      .thenAnswer((_) async => http.Response(
          fixture('account.json'),
          200,
      ),
    );
    
    

    【讨论】:

    • 太棒了,您解决了我的问题并描述了它失败的原因 - 非常非常有帮助:-) 我确实发现在使用 any() 之前我需要将以下内容添加到测试设置中: registerFallbackValue( uri.parse('fake.url.com/'));
    • 好!哦对了,你没看错,类型Uri需要注册FallbackValue。更新了我的答案
    • 我有同样的问题,但我似乎正确地模拟了,因为我所有的测试都通过了。我在这里发布了我的问题:stackoverflow.com/questions/69669624
    猜你喜欢
    • 1970-01-01
    • 2022-06-23
    • 2020-10-13
    • 2021-12-08
    • 2020-11-19
    • 1970-01-01
    • 2020-09-24
    • 2020-09-11
    • 2021-10-20
    相关资源
    最近更新 更多