如何为 dio 超时创建测试
How create test for dio timeout
我正在尝试使用 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:
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 创建超时测试?
你的方法有几个问题。
首先,您正在测试 async
方法,但并未 await
测试它。这将导致原始 Future
对象返回到 expect
函数,该函数将认为它是一个成功的调用,即使 future 最终抛出错误。您将需要 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>());
}
},
);
我正在尝试使用 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:
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 创建超时测试?
你的方法有几个问题。
首先,您正在测试 async
方法,但并未 await
测试它。这将导致原始 Future
对象返回到 expect
函数,该函数将认为它是一个成功的调用,即使 future 最终抛出错误。您将需要 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>());
}
},
);