
- 在APIEndpoints.swift中新增getUserInfo端点以支持获取用户信息。 - 在APIModels.swift中实现获取用户信息请求和响应模型,处理用户信息的请求与解析。 - 在UserInfoManager中新增方法以从服务器获取用户信息,并在登录成功后自动获取用户信息。 - 在SettingFeature中新增用户信息刷新状态管理,支持用户信息的刷新操作。 - 在SettingView中集成用户信息刷新按钮,提升用户体验。 - 在SplashFeature中实现自动获取用户信息的逻辑,优化用户登录流程。 - 在yanaAPITests中添加用户信息相关的单元测试,确保功能的正确性。
241 lines
11 KiB
Swift
241 lines
11 KiB
Swift
//
|
||
// yanaAPITests.swift
|
||
// yanaAPITests
|
||
//
|
||
// Created by P on 2025/5/27.
|
||
//
|
||
|
||
import XCTest
|
||
@testable import yana
|
||
|
||
final class yanaAPITests: XCTestCase {
|
||
|
||
override func setUpWithError() throws {
|
||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||
}
|
||
|
||
override func tearDownWithError() throws {
|
||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||
}
|
||
|
||
func testExample() throws {
|
||
// This is an example of a functional test case.
|
||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||
// Any test you write for XCTest can be annotated as throws and async.
|
||
// Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
|
||
// Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
|
||
}
|
||
|
||
func testPerformanceExample() throws {
|
||
// This is an example of a performance test case.
|
||
measure {
|
||
// Put the code you want to measure the time of here.
|
||
}
|
||
}
|
||
|
||
func testIDLoginRequest_Creation() {
|
||
// 测试ID登录请求的创建
|
||
let userID = "399113"
|
||
let password = "a123456"
|
||
|
||
let request = LoginHelper.createIDLoginRequest(userID: userID, password: password)
|
||
XCTAssertNotNil(request, "登录请求应该创建成功")
|
||
XCTAssertEqual(request?.endpoint, "/oauth/token", "端点应该正确")
|
||
XCTAssertEqual(request?.method, .POST, "请求方法应该是POST")
|
||
}
|
||
|
||
func testIDLoginResponse_Success() {
|
||
// 测试登录响应的成功解析
|
||
let successResponse = IDLoginResponse(
|
||
status: "success",
|
||
message: "登录成功",
|
||
code: 200,
|
||
data: IDLoginData(
|
||
accessToken: "test_token",
|
||
refreshToken: "refresh_token",
|
||
tokenType: "Bearer",
|
||
expiresIn: 3600,
|
||
scope: "read write",
|
||
userInfo: UserInfo(
|
||
userId: "123",
|
||
username: "testuser",
|
||
nickname: "Test User",
|
||
avatar: nil,
|
||
email: "test@example.com",
|
||
phone: "399113",
|
||
status: "active",
|
||
createTime: "2024-01-01",
|
||
updateTime: "2024-01-01"
|
||
)
|
||
)
|
||
)
|
||
|
||
XCTAssertTrue(successResponse.isSuccess, "响应应该标记为成功")
|
||
XCTAssertEqual(successResponse.data?.accessToken, "test_token", "访问令牌应该正确")
|
||
}
|
||
|
||
func testAccountModelFlow() {
|
||
// 测试完整的 AccountModel 流程
|
||
|
||
// 1. 模拟 oauth/token 响应(基于用户提供的真实数据)
|
||
let loginData = IDLoginData(
|
||
accessToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test",
|
||
refreshToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.refresh",
|
||
tokenType: "bearer",
|
||
expiresIn: 2591999,
|
||
scope: "read write",
|
||
userInfo: nil, // 真实API没有返回user_info
|
||
uid: 3184,
|
||
netEaseToken: "6fba51065b5e32ad18a935438517a1a9",
|
||
jti: "d3a82ddb-ea6f-4d2f-8dc7-7bdb3d6b9e87"
|
||
)
|
||
|
||
// 2. 从 IDLoginData 创建 AccountModel
|
||
let accountModel = AccountModel.from(loginData: loginData)
|
||
|
||
XCTAssertNotNil(accountModel, "应该能从IDLoginData创建AccountModel")
|
||
XCTAssertEqual(accountModel?.uid, "3184", "UID应该正确转换为字符串")
|
||
XCTAssertEqual(accountModel?.accessToken, "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test", "Access Token应该正确")
|
||
XCTAssertEqual(accountModel?.tokenType, "bearer", "Token类型应该正确")
|
||
XCTAssertEqual(accountModel?.netEaseToken, "6fba51065b5e32ad18a935438517a1a9", "网易云Token应该正确")
|
||
XCTAssertNil(accountModel?.ticket, "初始ticket应该为空")
|
||
|
||
// 3. 检查认证状态
|
||
XCTAssertTrue(accountModel?.hasValidAuthentication ?? false, "应该有有效的认证")
|
||
XCTAssertFalse(accountModel?.hasValidSession ?? true, "没有ticket时不应该有有效会话")
|
||
|
||
// 4. 模拟获取ticket后更新AccountModel
|
||
let ticketString = "eyJhbGciOiJIUzI1NiJ9.ticket"
|
||
let updatedAccountModel = accountModel?.withTicket(ticketString)
|
||
|
||
XCTAssertNotNil(updatedAccountModel, "应该能更新ticket")
|
||
XCTAssertEqual(updatedAccountModel?.ticket, ticketString, "Ticket应该正确设置")
|
||
XCTAssertTrue(updatedAccountModel?.hasValidSession ?? false, "有ticket时应该有有效会话")
|
||
|
||
// 5. 测试持久化和加载
|
||
if let finalAccountModel = updatedAccountModel {
|
||
UserInfoManager.saveAccountModel(finalAccountModel)
|
||
|
||
let loadedAccountModel = UserInfoManager.getAccountModel()
|
||
XCTAssertNotNil(loadedAccountModel, "应该能加载保存的AccountModel")
|
||
XCTAssertEqual(loadedAccountModel?.uid, "3184", "加载的UID应该正确")
|
||
XCTAssertEqual(loadedAccountModel?.accessToken, finalAccountModel.accessToken, "加载的Access Token应该正确")
|
||
XCTAssertEqual(loadedAccountModel?.ticket, ticketString, "加载的Ticket应该正确")
|
||
|
||
// 6. 测试向后兼容性
|
||
let userId = UserInfoManager.getCurrentUserId()
|
||
let accessToken = UserInfoManager.getAccessToken()
|
||
let ticket = UserInfoManager.getCurrentUserTicket()
|
||
|
||
XCTAssertEqual(userId, "3184", "向后兼容的用户ID应该正确")
|
||
XCTAssertEqual(accessToken, finalAccountModel.accessToken, "向后兼容的Access Token应该正确")
|
||
XCTAssertEqual(ticket, ticketString, "向后兼容的Ticket应该正确")
|
||
}
|
||
|
||
// 7. 清理
|
||
UserInfoManager.clearAllAuthenticationData()
|
||
XCTAssertNil(UserInfoManager.getAccountModel(), "清理后AccountModel应该为空")
|
||
XCTAssertNil(UserInfoManager.getCurrentUserId(), "清理后用户ID应该为空")
|
||
}
|
||
|
||
func testAccountModelWithRealAPIData() {
|
||
// 使用用户提供的真实API返回数据进行测试
|
||
let realAPIResponseData: [String: Any] = [
|
||
"uid": 3184,
|
||
"jti": "d3a82ddb-ea6f-4d2f-8dc7-7bdb3d6b9e87",
|
||
"token_type": "bearer",
|
||
"scope": "read write",
|
||
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiIyMzU2ODE0Iiwic2NvcGUiOlsicmVhZCIsIndyaXRlIl0sImF0aSI6ImQzYTgyZGRiLWVhNmYtNGQyZi04ZGM3LTdiZGIzZDZiOWU4NyIsImV4cCI6MTc1NTI0MjY5MiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9hY2NvdW50IiwiUk9MRV9NT0JJTEUiLCJST0xFX1VOSVRZIl0sImp0aSI6ImFiZjhjN2ZjLTllOWEtNDE2Yy04NTk2LTBkMWYxZWQyODU2MiIsImNsaWVudF9pZCI6ImVyYmFuLWNsaWVudCJ9.6i_9FnZvviuWYIoXDv9of7EDRyjRVxNbkiHayNUFxNw",
|
||
"netEaseToken": "6fba51065b5e32ad18a935438517a1a9",
|
||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NTQ2Mzc4OTIsInVzZXJfbmFtZSI6IjIzNTY4MTQiLCJhdXRob3JpdGllcyI6WyJST0xFX2FjY291bnQiLCJST0xFX01PQklMRSIsIlJPTEVfVU5JVFkiXSwianRpIjoiZDNhODJkZGItZWE2Zi00ZDJmLThkYzctN2JkYjNkNmI5ZTg3IiwiY2xpZW50X2lkIjoiZXJiYW4tY2xpZW50Iiwic2NvcGUiOlsicmVhZCIsIndyaXRlIl19.ynUptBtAoPVXz4J1AO8LbaAhmFRF4UnF4C-Ggj6Izpc",
|
||
"expires_in": 2591999
|
||
]
|
||
|
||
// 模拟JSON解析
|
||
do {
|
||
let jsonData = try JSONSerialization.data(withJSONObject: realAPIResponseData)
|
||
let loginData = try JSONDecoder().decode(IDLoginData.self, from: jsonData)
|
||
|
||
// 创建AccountModel
|
||
let accountModel = AccountModel.from(loginData: loginData)
|
||
|
||
XCTAssertNotNil(accountModel, "应该能从真实API数据创建AccountModel")
|
||
XCTAssertEqual(accountModel?.uid, "3184", "真实API数据的UID应该正确")
|
||
XCTAssertTrue(accountModel?.hasValidAuthentication ?? false, "真实API数据应该有有效认证")
|
||
|
||
debugInfoSync("✅ 真实API数据测试通过")
|
||
debugInfoSync(" UID: \(accountModel?.uid ?? "nil")")
|
||
debugInfoSync(" Access Token存在: \(accountModel?.accessToken != nil)")
|
||
debugInfoSync(" Token类型: \(accountModel?.tokenType ?? "nil")")
|
||
|
||
} catch {
|
||
XCTFail("解析真实API数据失败: \(error)")
|
||
}
|
||
}
|
||
}
|
||
|
||
// MARK: - User Info API Tests
|
||
extension yanaAPITests {
|
||
|
||
func testGetUserInfoRequest() {
|
||
// 测试获取用户信息请求创建
|
||
let uid = "12345"
|
||
let request = UserInfoHelper.createGetUserInfoRequest(uid: uid)
|
||
|
||
XCTAssertEqual(request.endpoint, "/user/get", "端点应该正确")
|
||
XCTAssertEqual(request.method, .GET, "请求方法应该是GET")
|
||
XCTAssertEqual(request.queryParameters?["uid"], uid, "UID参数应该正确")
|
||
XCTAssertFalse(request.shouldShowLoading, "不应该显示loading")
|
||
XCTAssertFalse(request.shouldShowError, "不应该显示错误")
|
||
}
|
||
|
||
func testGetUserInfoResponse() {
|
||
// 测试用户信息响应解析
|
||
let responseData: [String: Any] = [
|
||
"code": 200,
|
||
"message": "success",
|
||
"timestamp": 1640995200000,
|
||
"data": [
|
||
"user_id": "12345",
|
||
"username": "testuser",
|
||
"nickname": "测试用户",
|
||
"avatar": "https://example.com/avatar.jpg",
|
||
"email": "test@example.com",
|
||
"phone": "13800138000",
|
||
"status": "active",
|
||
"create_time": "2024-01-01 00:00:00",
|
||
"update_time": "2024-01-01 00:00:00"
|
||
]
|
||
]
|
||
|
||
do {
|
||
let jsonData = try JSONSerialization.data(withJSONObject: responseData)
|
||
let response = try JSONDecoder().decode(GetUserInfoResponse.self, from: jsonData)
|
||
|
||
XCTAssertTrue(response.isSuccess, "响应应该成功")
|
||
XCTAssertEqual(response.code, 200, "状态码应该正确")
|
||
XCTAssertNotNil(response.data, "用户信息数据应该存在")
|
||
|
||
if let userInfo = response.data {
|
||
XCTAssertEqual(userInfo.userId, "12345", "用户ID应该正确")
|
||
XCTAssertEqual(userInfo.username, "testuser", "用户名应该正确")
|
||
XCTAssertEqual(userInfo.nickname, "测试用户", "昵称应该正确")
|
||
}
|
||
|
||
debugInfoSync("✅ 用户信息响应解析测试通过")
|
||
|
||
} catch {
|
||
XCTFail("解析用户信息响应失败: \(error)")
|
||
}
|
||
}
|
||
|
||
func testUserInfoHelper() {
|
||
// 测试UserInfoHelper
|
||
let uid = "67890"
|
||
UserInfoHelper.debugGetUserInfoRequest(uid: uid)
|
||
|
||
let request = UserInfoHelper.createGetUserInfoRequest(uid: uid)
|
||
XCTAssertEqual(request.queryParameters?["uid"], uid, "Helper创建的请求应该正确")
|
||
}
|
||
}
|