❌ Helper 폴더는 NO!
✅ LemonLogTests 폴더가 정답입니다.
iOS 앱을 개발하다 보면,
“내가 만든 Core Data나 FileManager 로직이 잘 동작하는지”
직접 확인하고 싶을 때가 많아요.
그래서 보통 아래처럼 테스트 전용 클래스를 하나 만들어두죠 👇
final class DiaryTestManager {
static let shared = DiaryTestManager()
private init() {}
private let coreDataManager = DiaryCoreDataManager.shared
}
이 클래스는 앱 실행 중 사용자에게 보여지는 기능이 아니라,
“개발 중 내가 만든 Core Data 로직이 제대로 동작하는지 검증하기 위한 도구”예요.
그런데… 이걸 어디에 넣어야 할까요?
❌ 잘못된 선택: Helper 폴더
많은 초보 개발자들이 처음엔 이렇게 생각해요 👇
“테스트용 클래스니까 Helper 폴더 안에 넣어야지!”
하지만 이건 아주 위험한 설계예요.
| 문제점 | 설명 |
| ⚠️ 앱 번들에 포함됨 | 앱 빌드 시 사용자 기기에 함께 설치됩니다. |
| ⚠️ 내부 데이터 노출 위험 | 테스트용 로그나 더미 데이터가 앱 내부에 남을 수 있습니다. |
| ⚠️ 불필요한 용량 증가 | 테스트 전용 클래스가 릴리즈 버전에 포함됩니다. |
| ⚠️ 유지보수 혼란 | Helper 폴더에 테스트 코드가 섞이면 실제 앱 로직과 경계가 모호해집니다. |
즉, “사용자에게 필요 없는 코드”가 앱과 함께 배포되는 거예요.
테스트 코드는 앱 코드와 완전히 분리된 환경에서만 실행돼야 합니다.
✅ 올바른 선택: LemonLogTests 폴더
테스트 코드는 반드시 테스트 전용 폴더 (LemonLogTests) 안에 넣어야 합니다.
LemonLog/
┣ Helper/
┃ ┣ LogManager/
┃ ┗ DateFormatter/
┣ Manager/
┣ Model/
┣ View/
┣ ViewModel/
LemonLogTests/ ✅ 테스트 전용
┣ DiaryTestManager.swift
┗ DiaryCoreDataTests.swift
이 폴더는 앱 타겟과 완전히 분리된 테스트 전용 빌드 환경이에요.
즉, 앱을 실제로 실행할 땐 테스트 코드가 포함되지 않습니다.
💡 DiaryTestManager를 만든 이유
Core Data를 직접 테스트하려면 매번 이렇게 해야 해요 👇
let manager = DiaryCoreDataManager.shared
manager.saveDiary(model: dummy)
let result = manager.fetchDiaries(mode: .all)
그런데 이런 코드를 여러 테스트 함수마다 반복하면
중복이 많고 관리가 어려워져요.
그래서 “테스트만 담당하는 관리 객체”로 DiaryTestManager를 따로 만든 거예요.
✅ 역할 정리
| 역할 | 설명 |
| Core Data CRUD 통합 테스트 | save, fetch, update, delete 기능 검증 |
| 더미 데이터 생성 | 테스트용 EmotionDiaryModel을 자동 생성 |
| 데이터 초기화 | 이전 테스트에서 남은 데이터를 삭제 |
| 재사용성 확보 | 다른 테스트 클래스에서도 같은 로직 재사용 가능 |
⚙️ @testable import를 꼭 추가해야 하는 이유
테스트 코드 상단에는 반드시 이 구문이 필요해요 👇
@testable import LemonLog
이건 앱 내부의 internal 코드 (예: DiaryCoreDataManager, FileManager 등)에
접근할 수 있도록 허용하는 키워드예요.
테스트 타겟은 기본적으로 앱 모듈 내부에 접근할 수 없기 때문에
이걸 추가하지 않으면 "Cannot find 'DiaryCoreDataManager' in scope" 오류가 납니다.
🧩 Swift 6 이후의 변화 — MainActor 에러의 등장
DiaryCoreDataManager를 이렇게 선언했죠 👇
@MainActor
final class DiaryCoreDataManager {
static let shared = DiaryCoreDataManager()
}
그런데 Swift 6부터는 MainActor로 격리된 객체(shared)를
비동기 아닌 일반 클래스에서 직접 참조할 수 없어요.
그래서 아래와 같은 에러가 뜨는 거예요.
❌ “Main actor-isolated property ‘shared’ cannot be referenced from a nonisolated context”
해결 방법은 간단합니다.
테스트 클래스(DiaryTestManager)에 @MainActor를 붙여주면 돼요 👇
@MainActor
final class DiaryTestManager {
static let shared = DiaryTestManager()
private init() {}
private let coreDataManager = DiaryCoreDataManager.shared
}
이렇게 하면 MainActor 환경이 일치하기 때문에
Core Data 접근 시 스레드 충돌 없이 안전하게 테스트할 수 있습니다 ✅
🧪 실제 구조 예시
import XCTest
@testable import LemonLog
@MainActor
final class DiaryTestManager {
static let shared = DiaryTestManager()
private init() {}
private let coreDataManager = DiaryCoreDataManager.shared
}
final class DiaryCoreDataTests: XCTestCase {
private let testManager = DiaryTestManager.shared
func testSaveDiary() {
let diary = EmotionDiaryModel(
id: UUID(),
emotion: "happy_grade_1",
content: "오늘은 정말 행복했어요 🌞",
createdAt: Date(),
images: nil
)
testManager.save(diary) // ✅ Core Data에 저장
let fetched = testManager.fetch(by: diary.id)
XCTAssertNotNil(fetched)
}
}
📘 정리 요약
| 항목 | 잘못된 방식 | 올바른 방식 |
| 위치 | Helper 폴더 | ✅ LemonLogTests 폴더 |
| import 방식 | import LemonLog | ✅ @testable import LemonLog |
| MainActor 에러 해결 | 없음 | ✅ 테스트 클래스에도 @MainActor 적용 |
| 역할 | 앱 기능 도우미 | ✅ Core Data 테스트 관리 전용 |
| 결과 | 앱 번들 포함 ❌ | 테스트 환경 전용 ✅ |
✨ 마무리
“테스트 코드는 앱의 일부가 아닙니다.
앱을 검증하기 위한 별도의 세계입니다.”
Helper는 앱 기능을 “돕는 코드”를 담는 곳이고,
Tests는 “앱이 잘 작동하는지 검증하는 코드”를 담는 곳이에요.
📌 정비 도구는 공장에, 운전 기능은 자동차 안에.
같은 이유로 테스트 코드는 반드시 LemonLogTests 폴더에 있어야 합니다. ✅
'감정일기(가칭)' 카테고리의 다른 글
| 💥 Xcode 테스트 실행 시 “DSTROOT install style is not supported on this device.” 에러 해결법 (0) | 2025.10.20 |
|---|---|
| ⚙️ Core Data에서 catch가 작동하지 않는 이유 (0) | 2025.10.20 |
| 🍋 Core Data Fetch 고급 설계 — Predicate, Compound, FetchLimit 완전정복 (0) | 2025.10.20 |
| 🍋 Swift FileManager 설계 — private 유지하면서 안전하게 경로 노출하기 (0) | 2025.10.19 |
| 🚀 Swift 6에서 바뀐 Concurrency 규칙 완전 정리 (0) | 2025.10.19 |