Skip to content

Commit 99bbe58

Browse files
committed
chore: FCMTokenSyncHandler 동작 테스트를 추가
1 parent 892a13b commit 99bbe58

1 file changed

Lines changed: 176 additions & 0 deletions

File tree

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
//
2+
// FCMTokenSyncHandlerTests.swift
3+
// DevLogAppTests
4+
//
5+
// Created by opfic on 6/13/26.
6+
//
7+
8+
import Foundation
9+
import Testing
10+
import DevLogData
11+
@testable import DevLogApp
12+
13+
struct FCMTokenSyncHandlerTests {
14+
@Test("현재 FCM token 동기화 요청 시 token이 있으면 저장한다")
15+
func 현재_FCM_token_동기화_요청_시_token이_있으면_저장한다() async throws {
16+
let notificationCenter = NotificationCenter()
17+
let registrationObserver = NotificationObserver(
18+
notificationCenter: notificationCenter,
19+
name: .didRequestRemoteNotificationRegistration
20+
)
21+
let messagingService = PushMessagingServiceSpy(currentFCMToken: "current-token")
22+
let userService = UserServiceSpy()
23+
let handler = FCMTokenSyncHandler(
24+
messagingService: messagingService,
25+
userService: userService,
26+
notificationCenter: notificationCenter
27+
)
28+
29+
notificationCenter.post(name: .didRequestFCMTokenSync, object: nil)
30+
31+
try await waitUntil {
32+
await userService.updatedFCMTokens == ["current-token"]
33+
}
34+
#expect(registrationObserver.didReceiveNotification)
35+
_ = handler
36+
}
37+
38+
@Test("현재 FCM token 동기화 요청 시 token이 없으면 저장하지 않는다")
39+
func 현재_FCM_token_동기화_요청_시_token이_없으면_저장하지_않는다() async throws {
40+
let notificationCenter = NotificationCenter()
41+
let messagingService = PushMessagingServiceSpy(currentFCMToken: nil)
42+
let userService = UserServiceSpy()
43+
let handler = FCMTokenSyncHandler(
44+
messagingService: messagingService,
45+
userService: userService,
46+
notificationCenter: notificationCenter
47+
)
48+
49+
notificationCenter.post(name: .didRequestFCMTokenSync, object: nil)
50+
51+
try await Task.sleep(for: .milliseconds(100))
52+
#expect(await userService.updatedFCMTokens.isEmpty)
53+
_ = handler
54+
}
55+
56+
@Test("갱신된 FCM token 이벤트 수신 시 저장한다")
57+
func 갱신된_FCM_token_이벤트_수신_시_저장한다() async throws {
58+
let notificationCenter = NotificationCenter()
59+
let messagingService = PushMessagingServiceSpy(currentFCMToken: nil)
60+
let userService = UserServiceSpy()
61+
let handler = FCMTokenSyncHandler(
62+
messagingService: messagingService,
63+
userService: userService,
64+
notificationCenter: notificationCenter
65+
)
66+
67+
notificationCenter.post(
68+
name: .didRefreshFCMToken,
69+
object: nil,
70+
userInfo: ["fcmToken": "refreshed-token"]
71+
)
72+
73+
try await waitUntil {
74+
await userService.updatedFCMTokens == ["refreshed-token"]
75+
}
76+
_ = handler
77+
}
78+
79+
@Test("APNs token 이벤트 수신 시 APNs token을 적용하고 현재 FCM token을 저장한다")
80+
func APNs_token_이벤트_수신_시_APNs_token을_적용하고_현재_FCM_token을_저장한다() async throws {
81+
let notificationCenter = NotificationCenter()
82+
let messagingService = PushMessagingServiceSpy(currentFCMToken: "current-token")
83+
let userService = UserServiceSpy()
84+
let handler = FCMTokenSyncHandler(
85+
messagingService: messagingService,
86+
userService: userService,
87+
notificationCenter: notificationCenter
88+
)
89+
let deviceToken = Data([0x01, 0x02, 0x03])
90+
91+
notificationCenter.post(
92+
name: .didReceiveAPNSToken,
93+
object: nil,
94+
userInfo: ["deviceToken": deviceToken]
95+
)
96+
97+
try await waitUntil {
98+
await userService.updatedFCMTokens == ["current-token"]
99+
}
100+
#expect(messagingService.apnsTokens == [deviceToken])
101+
_ = handler
102+
}
103+
}
104+
105+
private actor UserServiceSpy: UserService {
106+
private(set) var updatedFCMTokens = [String]()
107+
108+
func upsertUser(_ response: AuthDataResponse) async throws { }
109+
func fetchUserProfile() async throws -> UserProfileResponse { fatalError() }
110+
func upsertStatusMessage(_ message: String) async throws { }
111+
112+
func updateFCMToken(_ fcmToken: String) async throws {
113+
updatedFCMTokens.append(fcmToken)
114+
}
115+
116+
func updateUserTimeZone() async throws { }
117+
}
118+
119+
private final class PushMessagingServiceSpy: PushMessagingService {
120+
private let currentFCMToken: String?
121+
private(set) var apnsTokens = [Data]()
122+
123+
init(currentFCMToken: String?) {
124+
self.currentFCMToken = currentFCMToken
125+
}
126+
127+
func setDelegate(_ delegate: PushMessagingServiceDelegate?) { }
128+
func setAPNSToken(_ deviceToken: Data) {
129+
apnsTokens.append(deviceToken)
130+
}
131+
func isNotificationAuthorized() async -> Bool { true }
132+
133+
func fetchFCMToken() async throws -> String? {
134+
currentFCMToken
135+
}
136+
}
137+
138+
private final class NotificationObserver {
139+
private(set) var didReceiveNotification = false
140+
private var token: NSObjectProtocol?
141+
private let notificationCenter: NotificationCenter
142+
143+
init(notificationCenter: NotificationCenter, name: Notification.Name) {
144+
self.notificationCenter = notificationCenter
145+
self.token = notificationCenter.addObserver(
146+
forName: name,
147+
object: nil,
148+
queue: nil
149+
) { [weak self] _ in
150+
self?.didReceiveNotification = true
151+
}
152+
}
153+
154+
deinit {
155+
if let token {
156+
notificationCenter.removeObserver(token)
157+
}
158+
}
159+
}
160+
161+
private func waitUntil(
162+
timeout: Duration = .seconds(1),
163+
pollInterval: Duration = .milliseconds(10),
164+
condition: @escaping @Sendable () async -> Bool
165+
) async throws {
166+
let deadline = ContinuousClock.now + timeout
167+
168+
while ContinuousClock.now < deadline {
169+
if await condition() {
170+
return
171+
}
172+
try await Task.sleep(for: pollInterval)
173+
}
174+
175+
Issue.record("조건을 만족하지 못함")
176+
}

0 commit comments

Comments
 (0)