본문 바로가기
감정일기(가칭)

🧩 LemonLog Core Data 테스트 콘솔 로그 분석

by 밤새는 탐험가89 2025. 10. 21.
728x90
SMALL
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가 테스트 중 두 번 초기화돼서 일시적으로 혼란스러워한 것일 뿐,
실제 앱 실행 시에는 단 한 번만 로드되므로 완벽히 정상 동작한다.”

728x90
LIST