// 单元测试:UserModel 的 JSON 解析兼容点 // // 为什么测它:CurrentUserExtension.fromJson 里有 4 个"抗后端漂移" // 的兼容点(见 user_model.dart 注释),任何一项回归都会导致线上 // 解析崩或字段丢,必须用测试锁死: // ① data 包装:接口返回 {code, message, data:{...}} 时取 data; // ② 字符串数字:userId/classId 后端可能返回 "820466383020136"; // ③ 缺字段兜底:后端漏字段时用默认值,不闪崩; // ④ toJson/fromJson 必须成对,否则缓存回填丢字段。 // // 运行:flutter test test/models/user_model_test.dart import 'package:flutter_test/flutter_test.dart'; import 'package:new_learn/core/models/user_model.dart'; void main() { group('CurrentUserExtension.fromJson', () { test('① data 包装:取 json["data"],忽略外层 code/message', () { final user = CurrentUserExtension.fromJson({ 'code': 200, 'message': 'ok', 'data': {'userId': 1001, 'userName': '小明', 'userPoints': 88.5}, }); expect(user.userId, 1001); expect(user.userName, '小明'); expect(user.userPoints, 88.5); }); test('① 直接返回(没有 data 包装)也支持', () { final user = CurrentUserExtension.fromJson({ 'userId': 7, 'userName': '小李', }); expect(user.userId, 7); expect(user.userName, '小李'); }); test('② 字符串数字:userId/classId/userPoints 传字符串能正确转换', () { final user = CurrentUserExtension.fromJson({ 'data': { 'userId': '820466383020136', // 大数必须 int 不丢精度 'classId': '12', 'userPoints': '105.5', 'graduationYear': '2026', }, }); expect(user.userId, 820466383020136); expect(user.classId, 12); expect(user.userPoints, 105.5); expect(user.graduationYear, 2026); }); test('② 非法字符串数字兜底为 0,不抛异常', () { final user = CurrentUserExtension.fromJson({ 'data': {'userId': 'abc', 'userPoints': 'xyz'}, }); expect(user.userId, 0); expect(user.userPoints, 0.0); }); test('③ 空 JSON:全部字段走默认值,不闪崩', () { final user = CurrentUserExtension.fromJson({}); expect(user.userId, 0); expect(user.userName, ''); expect(user.userPoints, 0.0); expect(user.levelName, ''); expect(user.isShowGuide, false); expect(user.isShowReport, false); expect(user.id, 0); }); test('④ toJson/fromJson 往返一致(缓存回填不丢字段)', () { const user = CurrentUserExtension( userId: 1001, userName: '小明', userPoints: 88.5, levelName: '青铜', avatar: 'https://x/a.png', className: '高三(1)班', classId: 12, gradeLevel: '高三', graduationYear: 2026, targetConfigId: 3, targetConfigName: '目标A', userAvatarStatus: 1, userAvatarReason: '待审核', isShowGuide: true, isShowReport: true, id: 99, ); final roundTrip = CurrentUserExtension.fromJson(user.toJson()); expect(roundTrip.userId, user.userId); expect(roundTrip.userName, user.userName); expect(roundTrip.userPoints, user.userPoints); expect(roundTrip.levelName, user.levelName); expect(roundTrip.className, user.className); expect(roundTrip.isShowGuide, user.isShowGuide); expect(roundTrip.userAvatarReason, user.userAvatarReason); }); }); group('UserPointLevel.fromJson', () { test('数字字段解析 + 默认值兜底', () { final level = UserPointLevel.fromJson({ 'userId': 1001, 'totalPoints': 500, 'level': 2, }); expect(level.userId, 1001); expect(level.totalPoints, 500); expect(level.level, 2); expect(level.levelUpPoints, 0); // 缺字段走默认值 final empty = UserPointLevel.fromJson({}); expect(empty.totalPoints, 0); expect(empty.level, 0); }); }); }