为什么:权威文档(AGENTS.md / CODING_STANDARDS.md)强制网络层用 dio,差异清单 A 组第 1 题
用户裁定选 A;原来用官方 http 是在无文档状态下按口头要求选的。
- ApiClient 改用 dio + BaseOptions(validateStatus 恒真、8s 超时、ResponseType.bytes 自行 UTF-8 解码)
- 新增 AuthHeaderInterceptor(Authorization / X-Device-Id)与 EnvelopeInterceptor
(解包 {code,message,data} + 错误码映射 + 401 判定)
- 401 → 刷新 → 重发一次在 ApiClient 里编排,刻意不放在拦截器内重发:dio 的排队拦截器
在回调里再发请求会自锁
- 接口层(auth_api/catalog_api)签名、全部 controller/logic/page 未改动
- 测试:新增假 dio adapter 替代 MockClient,断言口径一条未改;用例名改为 should_<期望>_when_<条件>;
新增 api_client_test(解包/错误映射/请求头/查询参数/跳过重试)与 live_auth_test(真实后端 POST 链路)
- pubspec:加 dio、移除已无引用的 http
- 实测:dart analyze lib test 零告警;flutter test 155 全过;真实联调(8081)GET/POST 链路均通
35 lines
1.2 KiB
Dart
35 lines
1.2 KiB
Dart
// Author: fruit.com.cn
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'package:nontonki/core/data/remote/api_client.dart';
|
|
import 'package:nontonki/core/data/remote/auth_api.dart';
|
|
|
|
/// 联调测试:直连本机客户端接口服务(8081)验证 **POST + JSON body + 错误码映射**。
|
|
///
|
|
/// 特意用"不存在的邮箱"登录:既能走完整的 POST 链路,又不会在库里留下测试数据。
|
|
/// 服务没启动时自动跳过,不影响日常 `flutter test`。
|
|
void main() {
|
|
final client = ApiClient(baseUrl: 'http://127.0.0.1:8081');
|
|
final api = AuthApi(client);
|
|
|
|
tearDownAll(client.close);
|
|
|
|
test('should surface a business error when signing in with an unknown email', () async {
|
|
try {
|
|
await api.login(
|
|
email: 'no-such-user-for-dio-check@example.com',
|
|
password: 'abcd1234',
|
|
deviceId: 'dio-check-device',
|
|
);
|
|
fail('不存在的邮箱不应该登录成功');
|
|
} on ApiException catch (error) {
|
|
// 关键点:错误码来自响应体(不是 HTTP 状态码),说明统一解包生效
|
|
expect(error.code, isNot(0));
|
|
expect(error.message, isNotEmpty);
|
|
} catch (_) {
|
|
markTestSkipped('客户端接口服务未启动,已跳过联调测试');
|
|
}
|
|
});
|
|
}
|