Failed to send CA Event for app launch measurements for ca_event_type: 0 event_name: com.apple.app_launch_measurement.FirstFramePresentationMetric
Failed to send CA Event for app launch measurements for ca_event_type: 1 event_name: com.apple.app_launch_measurement.ExtendedLaunchMetrics
Test Suite 'LemonLogTests' started at 2025-10-21 12:20:29.318.
Test Case '-[LemonLogTests.LemonLogTests testExample]' started.
Test Case '-[LemonLogTests.LemonLogTests testExample]' passed (0.048 seconds).
Test Case '-[LemonLogTests.LemonLogTests testPerformanceExample]' started.
/Users/kwonjeong-geun/Desktop/Project/LemonLog/LemonLogTests/LemonLogTests.swift:33: Test Case '-[LemonLogTests.LemonLogTests testPerformanceExample]' measured [Time, seconds] average: 0.000, relative standard deviation: 118.435%, values: [0.000050, 0.000009, 0.000007, 0.000007, 0.000006, 0.000006, 0.000006, 0.000006, 0.000006, 0.000006], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: "", baselineAverage: , polarity: prefers smaller, maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100
Test Case '-[LemonLogTests.LemonLogTests testPerformanceExample]' passed (1.322 seconds).
Test Case '-[LemonLogTests.LemonLogTests testRunAll]' started.
🚀 ==== LemonLog Core Data 테스트 시작 ====
✅ [persistentContainer:30] - Core Data 초기화 성공
CoreData: warning: Multiple NSEntityDescriptions claim the NSManagedObject subclass 'EmotionDiaryEntity' so +entity is unable to disambiguate.
CoreData: warning: Multiple NSEntityDescriptions claim the NSManagedObject subclass 'EmotionDiaryEntity' so +entity is unable to disambiguate.
CoreData: warning: 'EmotionDiaryEntity' (0x6000035009a0) from NSManagedObjectModel (0x600002120e10) claims 'EmotionDiaryEntity'.
CoreData: warning: 'EmotionDiaryEntity' (0x6000035009a0) from NSManagedObjectModel (0x600002120e10) claims 'EmotionDiaryEntity'.
CoreData: warning: 'EmotionDiaryEntity' (0x600003510c60) from NSManagedObjectModel (0x600002105c70) claims 'EmotionDiaryEntity'.
CoreData: warning: 'EmotionDiaryEntity' (0x600003510c60) from NSManagedObjectModel (0x600002105c70) claims 'EmotionDiaryEntity'.
CoreData: error: +[EmotionDiaryEntity entity] Failed to find a unique match for an NSEntityDescription to a managed object subclass
CoreData: error: +[EmotionDiaryEntity entity] Failed to find a unique match for an NSEntityDescription to a managed object subclass
✅ [saveImage(_:diaryID:index:):76] - 이미지 저장 성공: image_0.jpg
CoreData: warning: Multiple NSEntityDescriptions claim the NSManagedObject subclass 'DiaryImageEntity' so +entity is unable to disambiguate.
CoreData: warning: Multiple NSEntityDescriptions claim the NSManagedObject subclass 'DiaryImageEntity' so +entity is unable to disambiguate.
CoreData: warning: 'DiaryImageEntity' (0x600003500bb0) from NSManagedObjectModel (0x600002120e10) claims 'DiaryImageEntity'.
CoreData: warning: 'DiaryImageEntity' (0x600003500bb0) from NSManagedObjectModel (0x600002120e10) claims 'DiaryImageEntity'.
CoreData: warning: 'DiaryImageEntity' (0x600003510fd0) from NSManagedObjectModel (0x600002105c70) claims 'DiaryImageEntity'.
CoreData: warning: 'DiaryImageEntity' (0x600003510fd0) from NSManagedObjectModel (0x600002105c70) claims 'DiaryImageEntity'.
CoreData: error: +[DiaryImageEntity entity] Failed to find a unique match for an NSEntityDescription to a managed object subclass
CoreData: error: +[DiaryImageEntity entity] Failed to find a unique match for an NSEntityDescription to a managed object subclass
✅ [saveImage(_:diaryID:index:):76] - 이미지 저장 성공: image_1.jpg
✅ [saveContext():53] - Core Data 저장 성공
✅ [saveDiary(_:):99] - 감정일기 저장 성공 (F0C58DCC-6C82-4A72-99AF-F8C62D9C7A1F)
✅ [testSaveDiary():76] - ✅ [SAVE TEST] mask_grade_1 감정일기 저장 성공
✅ [fetchDiaries(mode:):129] - 총 1개의 감정일기 로드 완료
ℹ️ [testFetchAllDiaries():84] - ✅ [FETCH TEST] 총 1개의 감정일기 조회됨
ℹ️ [testFetchAllDiaries():86] - ▶️ mask_grade_1: 오늘의 감정은 mask_grade_1 🤔
✅ [performFetch(_:):336] - 총 0개의 감정일기 로드 완료
ℹ️ [testFetchByEmotion():95] - ✅ [SEARCH EMOTION] hungry_grade_3 감정일기 0개
✅ [performFetch(_:):336] - 총 0개의 감정일기 로드 완료
ℹ️ [testSearchByKeyword():103] - ✅ [SEARCH KEYWORD] 'angry_grade_1' 결과 0개
✅ [fetchLatestDiary():373] - 최근 감정일기 불러오기완료
✅ [testFetchLatestDiary():110] - ✅ [LATEST] 최근일기: mask_grade_1 / 오늘의 감정은 mask_grade_1 🤔
✅ [fetchDiaries(mode:):129] - 총 1개의 감정일기 로드 완료
✅ [deleteDiaryFolder(for:):120] - F0C58DCC-6C82-4A72-99AF-F8C62D9C7A1F 폴더 삭제 완료
✅ [saveImage(_:diaryID:index:):76] - 이미지 저장 성공: image_0.jpg
✅ [saveImage(_:diaryID:index:):76] - 이미지 저장 성공: image_1.jpg
✅ [saveImage(_:diaryID:index:):76] - 이미지 저장 성공: image_2.jpg
✅ [saveContext():53] - Core Data 저장 성공
✅ [updateDiary(_:):276] - 감정일기 수정 성공 (F0C58DCC-6C82-4A72-99AF-F8C62D9C7A1F)
✅ [testUpdateDiary():127] - ✅ [UPDATE TEST] 수정 성공
✅ [fetchDiaries(mode:):129] - 총 1개의 감정일기 로드 완료
✅ [deleteDiaryFolder(for:):120] - F0C58DCC-6C82-4A72-99AF-F8C62D9C7A1F 폴더 삭제 완료
✅ [saveContext():53] - Core Data 저장 성공
✅ [deleteDiary(by:):302] - 감정읽기 삭제 완료 [F0C58DCC-6C82-4A72-99AF-F8C62D9C7A1F]
✅ [testDeleteDiary():139] - 🗑️ [DELETE TEST] 삭제 성공
✅ [clearAllData():150] - 모든 메세지 삭제 완료 0
✅ ==== 모든 테스트 완료 ====
Test Case '-[LemonLogTests.LemonLogTests testRunAll]' passed (1.816 seconds).
Test Suite 'LemonLogTests' passed at 2025-10-21 12:20:32.505.
Executed 3 tests, with 0 failures (0 unexpected) in 3.185 (3.187) seconds
이제 이 콘솔 로그를 분석해보면,
현재 Core Data 테스트가 정확히 어떤 순서로 실행됐는지,
어디서 경고가 발생했는지,
최종적으로 어떤 의미인지를 명확히 정리할 수 있어요.
🚀 1️⃣ 테스트 전반 요약
| 항목 | 상태 |
| 테스트 클래스 | LemonLogTests |
| 실행된 테스트 | testExample, testPerformanceExample, testRunAll |
| 실행 환경 | 시뮬레이터 (정상) |
| 테스트 결과 | ✅ 전부 통과 (0 failure) |
| 총 소요 시간 | 약 3.18초 |
🧠 2️⃣ 로그 타임라인 분석
🟩 (1) 테스트 시작
🚀 ==== LemonLog Core Data 테스트 시작 ====
✅ [persistentContainer:30] - Core Data 초기화 성공
✅ Core Data 컨테이너(NSPersistentContainer)가 정상적으로 초기화됨을 의미.
즉, LemonLog.xcdatamodeld 기반의 실제 SQLite Persistent Store가 준비 완료 상태.
⚠️ (2) 경고: 중복된 Entity Description
CoreData: warning: Multiple NSEntityDescriptions claim the NSManagedObject subclass 'EmotionDiaryEntity'...
CoreData: error: +[EmotionDiaryEntity entity] Failed to find a unique match for an NSEntityDescription...
⚠️ 의미:
Core Data 모델 내에 EmotionDiaryEntity(또는 DiaryImageEntity)가
두 번 이상 로드된 상태라는 경고.
이건 테스트 환경에서
NSPersistentContainer가 두 번 초기화되거나,
앱 모듈과 테스트 모듈 양쪽에서
동일한 .xcdatamodeld 파일을 중복 로드할 때 발생한다.
💡 해결책 (선택사항)
- DiaryCoreDataManager.shared 내부에서 NSPersistentContainer를 다시 생성하지 않도록 주의.
- 테스트용 컨테이너와 실제 앱 컨테이너가 동일 인스턴스를 공유하도록 수정 가능.
- 경고 수준이지, 동작 자체에는 문제 없음. (CRUD는 모두 성공함)
✅ (3) 저장 테스트 (Create)
✅ [saveDiary(_:):99] - 감정일기 저장 성공
✅ [testSaveDiary():76] - ✅ [SAVE TEST] mask_grade_1 감정일기 저장 성공
더미 감정 mask_grade_1 로 일기 저장 성공.
Core Data 및 이미지 저장(image_0.jpg, image_1.jpg)까지 모두 성공.
저장 시점에 CoreData: error가 떴지만, 실제 insert 동작에는 영향 없음.
✅ (4) 조회 테스트 (Read)
✅ [fetchDiaries(mode:):129] - 총 1개의 감정일기 로드 완료
ℹ️ [testFetchAllDiaries():84] - ✅ [FETCH TEST] 총 1개의 감정일기 조회됨
ℹ️ [testFetchAllDiaries():86] - ▶️ mask_grade_1: 오늘의 감정은 mask_grade_1 🤔
저장된 1개의 일기를 정상적으로 fetch.
감정값과 내용까지 정확히 출력됨.
✅ (5) 감정별 / 키워드 검색
ℹ️ [testFetchByEmotion():95] - ✅ [SEARCH EMOTION] hungry_grade_3 감정일기 0개
ℹ️ [testSearchByKeyword():103] - ✅ [SEARCH KEYWORD] 'angry_grade_1' 결과 0개
테스트용 감정 hungry_grade_3 과 키워드 'angry_grade_1'은
저장된 데이터에 존재하지 않기 때문에
조회 결과 0개가 정상.
✅ 즉, “검색 조건 필터링이 정상 작동”했다는 뜻.
✅ (6) 최신 일기 조회
✅ [fetchLatestDiary():373] - 최근 감정일기 불러오기완료
✅ [testFetchLatestDiary():110] - ✅ [LATEST] 최근일기: mask_grade_1 / 오늘의 감정은 mask_grade_1 🤔
최근 저장된 일기를 정상적으로 인식.
“mask_grade_1”이 최신 일기로 반환됨.
✅ (7) 수정 테스트 (Update)
✅ [updateDiary(_:):276] - 감정일기 수정 성공
✅ [testUpdateDiary():127] - ✅ [UPDATE TEST] 수정 성공
content가 “수정된 내용입니다 ✏️”로 변경되고,
새로운 이미지(image_2.jpg)가 추가 저장됨.
Core Data 저장 성공으로 업데이트 완료.
✅ (8) 삭제 테스트 (Delete)
✅ [deleteDiary(by:):302] - 감정읽기 삭제 완료
✅ [testDeleteDiary():139] - 🗑️ [DELETE TEST] 삭제 성공
저장된 더미 데이터(F0C58DCC-6C82-4A72-99AF-F8C62D9C7A1F)가
Core Data와 이미지 폴더 양쪽에서 정상 삭제됨.
✅ (9) 전체 데이터 초기화
✅ [clearAllData():150] - 모든 메세지 삭제 완료 0
✅ ==== 모든 테스트 완료 ====
destroyPersistentStore()가 실행되어
테스트 중 사용된 SQLite 저장소 자체를 완전히 파괴(destroy)함.
즉, 모든 더미 데이터 삭제 완료 ✅
🧾 3️⃣ 전체 결과 요약
| 항목 | 결과 | 설명 |
| Core Data 초기화 | ✅ 성공 | Persistent Store 정상 로드 |
| 저장 (Create) | ✅ 성공 | 더미 일기 + 이미지 저장 완료 |
| 조회 (Read) | ✅ 성공 | 전체/필터/최신 모두 정상 작동 |
| 수정 (Update) | ✅ 성공 | 내용 및 이미지 변경 반영 |
| 삭제 (Delete) | ✅ 성공 | Core Data 및 폴더 데이터 삭제 |
| 저장소 초기화 | ✅ 성공 | 모든 데이터 및 SQLite 파일 제거 |
| 경고 | ⚠️ 있음 | Entity 중복 로딩 (테스트 환경 중복 로드) |
| 최종 결과 | ✅ All Tests Passed | 테스트 완전 통과 (0 failures) |
💡 4️⃣ 결론 — 테스트 결과 해석
✅ 정상 작동 요약
- Core Data CRUD 전 과정이 실제 Persistent Store에서 정확히 수행됨
- 이미지 파일 저장/삭제 로직까지 포함한 통합 테스트 성공
- 테스트 완료 후 clearAllData()로 DB 완전 초기화 → 데이터 오염 없음
⚠️ 경고(Warning)는 무시 가능하지만 개선 가능)
- "Multiple NSEntityDescriptions claim the NSManagedObject subclass"
→ 원인은 테스트 환경에서 동일한 데이터 모델이 중복 로드된 것
→ 앱 실행 중 문제는 아니지만,
테스트 시 NSPersistentContainer 중복 초기화를 한 번으로 통합하면 사라짐.
⚙️ 문제의 구조 요약
현재 구조를 보면 이렇게 돼 있어 👇
📦 LemonLog (App Target)
├─ DiaryCoreDataManager.shared → NSPersistentContainer(name: "LemonLog") 사용
└─ EmotionDiaryEntity, DiaryImageEntity …
📦 LemonLogTests (Test Target)
└─ DiaryTestManager.shared → NSPersistentContainer(name: "LemonLog") 또 생성
즉,
✅ 앱의 Core Data 매니저(DiaryCoreDataManager) 안에서도 컨테이너를 생성하고
✅ 테스트용 매니저(DiaryTestManager)에서도 동일한 모델 이름 "LemonLog"으로 새 컨테이너를 만들고 있어.
그럼 Xcode 입장에서는
“같은 모델(EmotionDiaryEntity)을 가진 두 개의 컨테이너가 존재하는데,
어떤 걸 써야 할지 모르겠어…”
이렇게 되면서 아래 경고가 뜨는 거야 👇
CoreData: warning: Multiple NSEntityDescriptions claim the NSManagedObject subclass 'EmotionDiaryEntity'
CoreData: error: +[EmotionDiaryEntity entity] Failed to find a unique match for an NSEntityDescription
🔍 원인 정리
| 원인 | 설명 |
| 중복 컨테이너 생성 | 앱(DiaryCoreDataManager)과 테스트(DiaryTestManager)에서 각각 NSPersistentContainer(name: "LemonLog")을 생성 |
| 동일 모델명 | 둘 다 "LemonLog" 모델을 로드 |
| 결과 | Core Data 런타임이 어떤 NSEntityDescription을 써야 할지 혼동함 |
| 영향 | 경고 및 로그 출력 (하지만 CRUD는 정상 작동) |
✅ 해결 방법 3가지
✅ 방법 1. 테스트 매니저에서 별도 모델명 사용 (권장)
테스트용 컨테이너 이름을 "LemonLogTest"로 바꾸면 완전히 독립된 컨텍스트로 작동해서
경고 없이 깔끔하게 테스트 가능 👇
final class DiaryTestManager {
static let shared = DiaryTestManager()
let container: NSPersistentContainer
private init() {
container = NSPersistentContainer(name: "LemonLogTest") // ✅ 이름 변경
container.loadPersistentStores { _, error in
if let error = error {
LogManager.print(.error, "테스트 저장소 로드 실패: \(error)")
}
}
}
}
단, 이때는 Xcode 내에서 .xcdatamodeld 복제본(LemonLogTest.xcdatamodeld)을 하나 만들어야 해.
내용은 동일해도 이름만 다르면 Core Data가 혼동하지 않아.
💡 추천 상황: 테스트용으로 독립 DB를 쓰고 싶을 때
✅ 방법 2. 기존 CoreDataManager의 컨테이너를 재사용
테스트 매니저에서는 새 컨테이너를 만들지 않고,
앱에서 사용하는 DiaryCoreDataManager.shared.container를 재활용하면 중복 생성이 없어져.
final class DiaryTestManager {
static let shared = DiaryTestManager()
let container: NSPersistentContainer
private init() {
container = DiaryCoreDataManager.shared.container // ✅ 기존 컨테이너 재사용
}
}
💡 추천 상황: 실제 Persistent Store를 대상으로 테스트하고 싶을 때
⚠️ 단, 이 경우 테스트 중 데이터가 앱 DB에 반영되므로 clearAllData() 필수
✅ 방법 3. In-memory Store 사용
테스트용 컨테이너는 그대로 두되,
저장소 타입을 NSInMemoryStoreType으로 지정하면
실제 SQLite가 생성되지 않아 중복 로드 문제를 회피할 수도 있어 👇
let description = NSPersistentStoreDescription()
description.type = NSInMemoryStoreType
container.persistentStoreDescriptions = [description]
container.loadPersistentStores { _, error in ... }
💡 추천 상황: CRUD 로직만 검증하고 실제 DB를 건드리고 싶지 않을 때
✅ 정리하자면
| 해결 방법 | 장점 | 주의점 |
| 1. 모델 이름 변경 (LemonLogTest) | 완전히 독립된 테스트 환경, 경고 없음 | 모델 복제 필요 |
| 2. CoreDataManager 재사용 | 실제 DB 기반 테스트 가능 | 데이터 오염 주의 |
| 3. In-memory Store | 빠르고 깨끗함, 테스트 간 충돌 없음 | 영구 저장소 테스트 불가 |
“이 경고는 Core Data가 테스트 중 두 번 초기화돼서 일시적으로 혼란스러워한 것일 뿐,
실제 앱 실행 시에는 단 한 번만 로드되므로 완벽히 정상 동작한다.”
'감정일기(가칭)' 카테고리의 다른 글
| 🍋 DiaryStore 설계 총정리 — “하나의 진실(Single Source of Truth)” 패턴으로 Core Data 관리하기 (0) | 2025.10.23 |
|---|---|
| 🧩 @Published vs CurrentValueSubject — Combine에서의 타이밍 차이 완벽 정리 (0) | 2025.10.22 |
| 🚀 Xcode에서 Core Data CRUD 테스트 실행하기 (0) | 2025.10.21 |
| 🧠 Core Data CRUD 테스트 자동화 — DiaryTestManager 완전 해설 (0) | 2025.10.21 |
| 💥 Xcode 테스트 실행 시 “DSTROOT install style is not supported on this device.” 에러 해결법 (0) | 2025.10.20 |