dev._.note

[Swift] XCTest란? 본문

TIL (Today I Learned)

[Swift] XCTest란?

Laena 2024. 3. 5. 08:35

XCTest

코어데이터 테스트를 하느라 삽질을 하고있었는데

튜터님이 XCTest를 알려주셨다! 🤔

메모를 마구잡이로 한것을 조금 정리한것

 

개요 : XCTest는 애플이 제공하는 프레임워크로, iOS 및 macOS 앱의 유닛 테스트와 UI 테스트를 위해 사용. XCTest를 구성하고 사용하는 방법에 대한 요약을 제공.

테스트 프로젝트 구조 설정:

  • 프로젝트 내의 폴더 구조와 동일하게 테스트 타겟의 폴더 구조를 설정. 테스트를 쉽게 찾고 관리할 수 있음.

유닛 테스트 작성:

  • @testable 키워드를 사용하여 테스트 대상의 내부 구성 요소에 접근할 수 있습니다. 이를 통해 internal 또는 public 접근 수준을 가진 코드에 대한 테스트가 가능.
  • XCTAssertTrue 함수 : 사용하여 조건이 참인지 확인. 테스트가 통과하려면 조건이 참이어야함.
  • XCTAssertFalse 함수 : 사용하여 조건이 거짓인지 확인. 테스트가 통과하려면 조건이 거짓이어야함.

SRP(Single Responsibility Principle) 준수:

  • 각 테스트 케이스는 한 가지의 기능만을 테스트 이는 테스트의 명확성과 유지보수성을 UP !

Core Data 테스트:

  • Core Data 관련 코드를 테스트할 때는 CRUD(생성, 읽기, 업데이트, 삭제) 작업과 관련된 흐름을 테스트
  • Core Data는 컨텍스트에 의존적이기 때문에 테스트하기 어려울 있으므로 이를 위해 모의 컨텍스트를 사용하는 것을 고려할 수 있음.
  • 테스트에서는 특정 작업 후 데이터가 실제로 추가되었는지 확인하기 위해 카운트를 사용.

 

테스트코드

import XCTest
@testable import ToDwoong

final class ToDwoongTests: XCTestCase {

    // MARK: - properties

    var coreDataManager: CoreDataManager!

    override func setUpWithError() throws {
        try super.setUpWithError()
        coreDataManager = CoreDataManager.shared
    }

    override func tearDownWithError() throws {
        coreDataManager = nil
        try super.tearDownWithError()
    }

    // 성공 케이스: Todo 생성
    func testCreateTodoSuccess() throws {
        // Given
        let title = "Test Todo2"
        let dueDate = Date()
        let isCompleted = false

        // When
        coreDataManager.createTodo(title: title,
                                   place: nil,
                                   dueDate: dueDate,
                                   dueTime: nil,
                                   isCompleted: isCompleted,
                                   timeAlarm: false,
                                   placeAlarm: false,
                                   category: nil)

        // Then
        let todos = coreDataManager.readTodos()
        XCTAssertFalse(todos.isEmpty) // 생성된 Todo가 비어있지 않아야 함
        XCTAssertEqual(todos.first?.title, title) // 생성된 Todo의 제목이 일치해야 함
        print("todo 생성")
    }

    // 실패 케이스: Todo 생성 - 제목 누락
    func testCreateTodoFailure() throws {
        // Given
        let title = ""

        // When
        coreDataManager.createTodo(title: title,
                                   place: nil,
                                   dueDate: nil,
                                   dueTime: nil,
                                   isCompleted: false,
                                   timeAlarm: false,
                                   placeAlarm: false,
                                   category: nil)

        // Then
        let todos = coreDataManager.readTodos()
        XCTAssertTrue(todos.isEmpty) // 빈 제목으로 생성된 Todo는 존재하지 않아야 함
    }

    // 성공 케이스: 모든 Todo를 읽기
    func testReadAllTodosSuccess() throws {
        // Given
        let titles = ["Todo 1", "Todo 2", "Todo 3"]
        for title in titles {
            coreDataManager.createTodo(title: title,
                                       place: nil,
                                       dueDate: nil,
                                       dueTime: nil,
                                       isCompleted: false,
                                       timeAlarm: false,
                                       placeAlarm: false,
                                       category: nil)
        }

        // When
        let todos = coreDataManager.readTodos()

        // Then
        XCTAssertEqual(todos.count, titles.count) // 읽어온 Todo 수는 생성한 Todo 수와 같아야 함
        for (index, todo) in todos.enumerated() {
            XCTAssertEqual(todo.title, titles[index]) // 읽어온 Todo의 제목은 생성한 Todo의 제목과 일치해야 함
        }
    }

    // 실패 케이스: 모든 Todo를 읽기 - Todo가 하나도 없는 경우
    func testReadAllTodosFailure() throws {
        // Given
        let todosBeforeRead = coreDataManager.readTodos()

        // When
        let todos = coreDataManager.readTodos()

        // Then
        XCTAssertTrue(todosBeforeRead.isEmpty) // 읽기 전에는 Todo가 비어 있어야 함
        XCTAssertTrue(todos.isEmpty) // 읽어온 Todo도 비어 있어야 함
    }

    // 성공 케이스: Todo 업데이트
    func testUpdateTodoSuccess() throws {
        // Given
        let title = "Test Todo"
        let updatedTitle = "Updated Todo"
        let dueDate = Date()
        let updatedDueDate = Date(timeIntervalSinceNow: 3600) // 1시간 뒤
        let isCompleted = false
        let updatedIsCompleted = true
        coreDataManager.createTodo(title: title,
                                   place: nil,
                                   dueDate: dueDate,
                                   dueTime: nil,
                                   isCompleted: isCompleted,
                                   timeAlarm: false,
                                   placeAlarm: false,
                                   category: nil)

        // When
        let todosBeforeUpdate = coreDataManager.readTodos()
        let todoToUpdate = todosBeforeUpdate.first!
        coreDataManager.updateTodo(todo: todoToUpdate,
                                   newTitle: updatedTitle,
                                   newPlace: "",
                                   newDate: updatedDueDate,
                                   newTime: nil,
                                   newCompleted: updatedIsCompleted,
                                   newTimeAlarm: false,
                                   newPlaceAlarm: false,
                                   newCategory: nil)

        // Then
        let todosAfterUpdate = coreDataManager.readTodos()
        XCTAssertFalse(todosAfterUpdate.isEmpty) // 업데이트 후 Todo가 비어있지 않아야 함
        XCTAssertEqual(todosBeforeUpdate.count, todosAfterUpdate.count) // 업데이트 전후의 Todo 수는 동일해야 함
        XCTAssertEqual(todosAfterUpdate.first?.title, updatedTitle) // 업데이트된 Todo의 제목이 변경되어야 함
        XCTAssertEqual(todosAfterUpdate.first?.dueDate, updatedDueDate) // 업데이트된 Todo의 만료일이 변경되어야 함
        XCTAssertEqual(todosAfterUpdate.first?.isCompleted, updatedIsCompleted) // 업데이트된 Todo의 완료 여부가 변경되어야 함
    }

    // 실패 케이스: Todo 업데이트 - 존재하지 않는 Todo 업데이트 시도
    func testUpdateTodoFailure() throws {
        // Given
        let todosBeforeUpdate = coreDataManager.readTodos()

        // When
        let nonExistingTodo = Todo() // 존재하지 않는 Todo 인스턴스 생성
        coreDataManager.updateTodo(todo: nonExistingTodo,
                                   newTitle: "Updated Todo",
                                   newPlace: "",
                                   newDate: Date(),
                                   newTime: nil,
                                   newCompleted: true,
                                   newTimeAlarm: false,
                                   newPlaceAlarm: false,
                                   newCategory: nil)

        // Then
        let todosAfterUpdate = coreDataManager.readTodos()
        XCTAssertEqual(todosBeforeUpdate.count, todosAfterUpdate.count) // 업데이트 전후의 Todo 수는 동일해야 함
    }

    // 성공 케이스: Todo 삭제
    func testDeleteTodoSuccess() throws {
        // Given
        let title = "Test Todo"
        let dueDate = Date()
        let isCompleted = false
        coreDataManager.createTodo(title: title,
                                   place: nil,
                                   dueDate: dueDate,
                                   dueTime: nil,
                                   isCompleted: isCompleted,
                                   timeAlarm: false,
                                   placeAlarm: false,
                                   category: nil)

        // When
        let todosBeforeDelete = coreDataManager.readTodos()
        let todoToDelete = todosBeforeDelete.first!
        coreDataManager.deleteTodo(todo: todoToDelete)

        // Then
        let todosAfterDelete = coreDataManager.readTodos()
        XCTAssertTrue(todosBeforeDelete.count > todosAfterDelete.count) // 삭제 후 Todo 수가 줄어들어야 함
    }

    // 실패 케이스: Todo 삭제 - 없는 Todo 삭제 시도
    func testDeleteTodoFailure() throws {
        // Given
        let todosBeforeDelete = coreDataManager.readTodos()

        // When
        let nonExistingTodo = Todo() // 존재하지 않는 Todo 인스턴스 생성
        coreDataManager.deleteTodo(todo: nonExistingTodo)

        // Then
        let todosAfterDelete = coreDataManager.readTodos()
        XCTAssertEqual(todosBeforeDelete.count, todosAfterDelete.count) // 삭제 전과 후의 Todo 수가 동일해야 함
    }

    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.
        }
    }
}

'TIL (Today I Learned)' 카테고리의 다른 글

[TIL] 240216_TIL  (0) 2024.02.16
[TIL] 240215_TIL  (0) 2024.02.15
[TIL] 240208_TIL  (0) 2024.02.09
[TIL] 240103_TIL  (1) 2024.01.03
[TIL] 231220_TIL  (0) 2023.12.20