
本教程将详细指导如何在flutter应用中,使用mockito框架对基于dio库实现的post网络请求进行单元测试,特别是针对登录认证场景。文章将演示如何模拟dio的`post`方法,返回预期的响应数据,从而验证业务逻辑的正确性,确保代码质量和可维护性。
在Flutter开发中,网络请求是常见的业务场景,而Dio是一个功能强大且广泛使用的HTTP客户端。为了确保应用的网络交互逻辑健壮可靠,进行单元测试至关重要。本教程将以一个登录认证的POST请求为例,详细讲解如何结合Mockito库来模拟Dio的行为,从而在不依赖真实网络的情况下测试我们的业务逻辑。
首先,我们来看一个典型的登录认证服务。该服务使用Dio发起POST请求,尝试通过用户名和密码获取访问令牌。
import 'package:dio/dio.dart';
import 'package:fluttertoast/fluttertoast.dart'; // 实际测试中通常会mock或忽略UI组件
// 假设的API服务类,提供基础URL
class Apiservices {
final String baseurl = "https://api.example.com/auth/token"; // 替换为你的实际登录API
}
class AuthenticationService {
final Dio _dio;
String? accessToken;
String? refreshToken;
final Apiservices _apiServices = Apiservices();
AuthenticationService(this._dio); // 注入Dio实例
/// 发起登录认证请求
/// 成功则返回accessToken,失败则返回DioError的字符串表示
Future<String?> authentication(String mobileNumber, String password) async {
dynamic data = {
"username": mobileNumber,
"password": password,
"grant_type": "password",
"client_id": "client_id"
};
try {
final response = await _dio.post(
_apiServices.baseurl,
data: data,
options: Options(headers: {
"Content-Type": "application/x-www-form-urlencoded"
}),
);
if (response.statusCode == 200) {
accessToken = response.data["access_token"];
refreshToken = response.data["refresh_token"];
// Fluttertoast.showToast(msg: "Successfully Logged in"); // UI交互,单元测试中通常不直接测试
return accessToken;
}
} on DioError catch (e) {
// Fluttertoast.showToast(msg: "Something went wrong"); // UI交互
return e.toString(); // 返回错误信息字符串
}
return null; // 如果try块中没有返回,且没有发生DioError,则返回null
}
}在这个AuthenticationService中,authentication方法负责构建请求体、发送POST请求,并根据响应状态码处理结果。在单元测试中,我们希望模拟_dio.post的行为,以验证authentication方法在不同响应下的逻辑。
为了进行单元测试,我们需要以下依赖:
在pubspec.yaml中添加或更新依赖:
dev_dependencies:
flutter_test:
sdk: flutter
mockito: ^5.4.4 # 请使用最新版本
build_runner: ^2.4.8 # 请使用最新版本
mockito_annotations: ^2.3.0 # 请使用最新版本然后运行 flutter pub get。
接下来,我们需要为Dio类生成一个模拟类。在你的测试文件(例如 test/authentication_service_test.dart)的顶部,添加以下内容:
// test/authentication_service_test.dart import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:dio/dio.dart'; import 'package:mockito/annotations.dart'; // 导入你的服务文件 import 'package:your_app_name/authentication_service.dart'; // 替换为你的实际路径 // 使用 @GenerateMocks 注解为 Dio 类生成 Mock 类 @GenerateMocks([Dio]) import 'authentication_service_test.mocks.dart'; // 这将在运行 build_runner 后生成
在添加 @GenerateMocks 注解后,运行以下命令来生成模拟文件: flutter pub run build_runner build 这会生成一个 authentication_service_test.mocks.dart 文件,其中包含 MockDio 类。
现在我们可以编写单元测试了。核心思想是使用 when().thenAnswer() 或 when().thenThrow() 来控制 MockDio 对象的行为。
当登录请求成功时,我们期望authentication方法返回一个访问令牌。
// 模拟成功的登录响应数据
final Map<String, dynamic> loginSuccessResponse = {
"access_token": "mock_access_token_123",
"refresh_token": "mock_refresh_token_456",
"expires_in": 3600,
"token_type": "Bearer"
};
void main() {
late MockDio mockDio;
late AuthenticationService authService;
// 在每个测试运行前初始化模拟对象和待测试服务
setUp(() {
mockDio = MockDio();
authService = AuthenticationService(mockDio);
});
group('AuthenticationService', () {
test('认证成功时应返回访问令牌并设置accessToken', () async {
// Arrange (安排): 设置模拟Dio的行为
when(mockDio.post(
Apiservices().baseurl, // 匹配请求的URL
data: anyNamed('data'), // 匹配任何名为'data'的参数
options: anyNamed('options'), // 匹配任何名为'options'的参数
)).thenAnswer((_) async => Response(
requestOptions: RequestOptions(path: Apiservices().baseurl), // 必须提供 RequestOptions
data: loginSuccessResponse,
statusCode: 200,
));
// Act (执行): 调用待测试的方法
final result = await authService.authentication("test_mobile", "test_password");
// Assert (断言): 验证结果是否符合预期
expect(result, isA<String>()); // 期望返回一个字符串
expect(result, loginSuccessResponse["access_token"]); // 期望返回正确的访问令牌
expect(authService.accessToken, loginSuccessResponse["access_token"]); // 验证服务内部的accessToken是否被设置
// 验证 Dio 的 post 方法是否被正确调用了一次
verify(mockDio.post(
Apiservices().baseurl,
data: anyNamed('data'),
options: anyNamed('options'),
)).called(1);
});
});
}代码解释:
当登录请求失败时,例如服务器返回400错误或网络连接问题,我们期望authentication方法捕获DioError并返回其字符串表示。
// 模拟失败的登录响应数据
final Map<String, dynamic> loginFailureResponse = {
"error": "invalid_grant",
"error_description": "Bad credentials"
};
// ... (main, setUp, group 保持不变)
group('AuthenticationService', () {
// ... (成功测试用例)
test('认证失败时应返回DioError的字符串表示', () async {
// Arrange: 设置模拟Dio在post请求时抛出 DioError
final dioError = DioError(
requestOptions: RequestOptions(path: Apiservices().baseurl),
response: Response(
requestOptions: RequestOptions(path: Apiservices().baseurl),
data: loginFailureResponse, // 可以包含错误响应体
statusCode: 400,
),
type: DioErrorType.response, // 指定错误类型
error: "Bad credentials", // 错误信息
);
when(mockDio.post(
Apiservices().baseurl,
data: anyNamed('data'),
options: anyNamed('options'),
)).thenThrow(dioError); // 模拟抛出 DioError
// Act: 调用待测试的方法
final result = await authService.authentication("wrong_mobile", "wrong_password");
// Assert: 验证结果
expect(result, isA<String>()); // 期望返回一个字符串
expect(result, contains("DioError")); // 期望字符串中包含 "DioError"
expect(result, contains("Bad credentials")); // 期望包含具体的错误信息
expect(authService.accessToken, isNull); // 验证accessToken未被设置
verify(mockDio.post(
Apiservices().baseurl,
data: anyNamed('data'),
options: anyNamed('options'),
)).called(1);
});
});代码解释:
以下是包含所有必要部分的完整单元测试文件示例:
// test/authentication_service_test.mocks.dart (此文件由 build_runner 自动生成,请勿手动修改)
// import 'package:mockito/mockito.dart';
// import 'package:dio/dio.dart';
// class MockDio extends Mock implements Dio {}
// test/authentication_service_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:dio/dio.dart';
import 'package:mockito/annotations.dart';
// 导入你的服务文件
import 'package:your_app_name/authentication_service.dart'; // 替换为你的实际路径
// 使用 @GenerateMocks 注解为 Dio 类生成 Mock 类
@GenerateMocks([Dio])
import 'authentication_service_test.mocks.dart'; // 运行 `flutter pub run build_runner build` 后生成
// 模拟成功的登录响应数据
final Map<String, dynamic> loginSuccessResponse = {
"access_token": "mock_access_token_123",
"refresh_token": "mock_refresh_token_456",
"expires_in": 3600,
"token_type": "Bearer"
};
// 模拟失败的登录响应数据
final Map<String, dynamic> loginFailureResponse = {
"error": "invalid_grant",
"error_description": "Bad credentials"
};
void main() {
late MockDio mockDio;
late AuthenticationService authService;
// 在每个测试运行前初始化模拟对象和待测试服务
setUp(() {
mockDio = MockDio();
authService = AuthenticationService(mockDio);
});
group('AuthenticationService', () {
test('认证成功时应返回访问令牌并设置accessToken', () async {
// Arrange (安排):以上就是Flutter Dio POST请求的Mockito单元测试指南的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号