【问题标题】:How create test for dio timeout如何为 dio 超时创建测试
【发布时间】:2021-03-23 17:59:05
【问题描述】:

我正在尝试使用 Dio 创建超时测试,我希望得到类型为 CONNECT_TIMEOUT 的 DioError 然后抛出自定义异常

我的测试我用 Mockito 模拟 Dio 并尝试抛出 DioError

test(
      'Should throw [ConnectionTimeOutException] when reach timeout',
      () async {
        //arange
        when(mockNetworkInfo.isConnected).thenAnswer((_) async => true);
        when(mockDio.post(paths.login, data: tParams.toJson())).thenThrow(
            (_) async => DioError(type: DioErrorType.CONNECT_TIMEOUT));
        //act
        final call = loginDataSource.login;
        //assert
        expect(() => call(params: tParams),
            throwsA(TypeMatcher<ConnectTimeOutException>()));
      },
    );

我的数据源类:

class LoginDataSourceImpl implements LoginDataSource {
  final Dio dio;
  final NetworkInfo networkInfo;

  LoginDataSourceImpl({@required this.dio, @required this.networkInfo});

  @override
  Future<CredencialModel> login({@required Params params}) async {
    if (!await networkInfo.isConnected) {
      throw NoNetworkException();
    }

    try {
      final response = await dio.post(paths.login, data: params.toJson());
      if (response.statusCode == 200) {
        return CredencialModel.fromJson(response.data);
      } else if (response.statusCode == 400) {
        final error = ResponseError.fromJson(response.data);
        switch (error.error) {
          case 'invalid_request':
            throw InvalidRequestException();
            break;
          case 'invalid_device':
            throw InvalidDeviceException();
            break;
          case 'invalid_user_credentials':
            throw InvalidUserCredentialException();
            break;
          case 'user_disabled':
            throw UserDisableException();
          default:
            throw UnknowException();
        }
      } else if (response.statusCode == 500) {
        throw ServerException();
      } else {
        throw UnknowException();
      }
    } on DioError catch (e) {
      if (e.type == DioErrorType.CONNECT_TIMEOUT) {
        throw ConnectTimeOutException();
      } else if (e.type == DioErrorType.RECEIVE_TIMEOUT) {
      } else {
        throw UnknowException();
      }
    }
  }
}

测试结果是:

Expected: throws <Instance of 'ConnectTimeOutException'>
  Actual: <Closure: () => Future<CredencialModel>>
   Which: threw <Closure: (dynamic) => DioError>
stack package:mockito/src/mock.dart 385:7    

如何解决这个问题并使用 Dio 创建超时测试?

【问题讨论】:

  • 你可以尝试在那个call 上扔一个await
  • 另外,thenThrow 接受您传递给它的任何对象并将其作为错误抛出。你给了它一个闭包对象。该闭包不会被调用,只是被抛出。将其更改为 thenThrow(DioError(type: DioErrorType.CONNECT_TIMEOUT))
  • 你是对的@Abion47,谢谢,请把你的评论作为答案,这样我就可以标记为解决方案。

标签: flutter unit-testing dart dio


【解决方案1】:

您的方法存在一些问题。

首先,您正在测试async 方法,但您没有awaiting 它。这将导致原始的 Future 对象返回到 expect 函数,该函数将认为它是一个成功的调用,即使未来最终抛出一个错误。你需要await你的电话,尽管这样做是因为传递给expect的闭包很尴尬。我建议将异步调用包装在 try/catch 中。

其次,您正在为 Mockito 的 thenThrow 方法提供一个闭包。这个方法接受你给它的任何东西并将它用作实际的抛出值,所以它不会调用你传递给它的闭包——它只会按原样抛出它。

解决这两个问题,你最终会得到这个:

test(
  'Should throw [ConnectionTimeOutException] when reach timeout',
  () async {
    // arrange
    when(mockNetworkInfo.isConnected)
      .thenAnswer(true);
    when(mockDio.post(paths.login, data: tParams.toJson()))
      .thenThrow(DioError(type: DioErrorType.CONNECT_TIMEOUT));

    // act
    final call = loginDataSource.login;

    // assert
    try {
      await call(params: tParams);
    } catch(e) {
      expect(e, isInstanceOf<ConnectTimeOutException>());
    }
  },
);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-20
    • 2013-09-10
    • 1970-01-01
    • 1970-01-01
    • 2011-02-21
    • 2021-05-30
    • 2018-10-08
    • 1970-01-01
    相关资源
    最近更新 更多