swift 복습

Unit test

섭섭's 2024. 10. 11. 19:17

 

Swift에서는 XCTest라는 기본 도구를 제공하기 때문에 빠르게 유닛 테스트를 할 수 있습니다.

 

유닛 테스트의 목적과 장점

 

1.유닛 테스트는 개별 함수나 메서드가 의도대로 동작하는지 확인하는 역할을 가지고 있습니다.

   코드의 정확성과 안정성을 확보 할 수 있습니다.

 

2.코드베이스에 변경이 생기면 유닛테스트를 통하여 기존 기능이 정상 작동하는지를 빠르게 확인 할 수 있습니다.

 

3.테스트가 실패했을 때 오류 발생 지점을 쉽게 알 수 있기 때문에 디버깅이 쉬워집니다.

 

4.코드 리팩토링시 안정성을 가지게 됩니다. 


프로젝트 생성시 유닛 테스트 포함

 

위의 사진을 보면 "Testing System 옵션 항목에 " Swift Testing with XCTest UI Tests" 가 선택되어 있습니다.

 

해당 옵션은 자동으로 XCTest 기반의 유닛 테스트 타깃과 테스트 파일을 프로젝트에 포함하는 옵션 입니다.

 

기존 프로젝트에 테스트 타깃 추가방법

 

 

Xcode 상단 메뉴에서 File->New->Target... 을 선택합니다.

 

 

 

 

프로젝트에 테스트 타깃과 기본 테스트 파일이 생성된 것을 확인할 수 있습니다.

 

 

프로젝트에 테스트 타깃과 기본 테스트 파일이 생성된 것을 확인할 수 있습니다.


유닛 테스트 클래스 작성해보기

기본 테스트 파일을 열어보게 되면

import Testing

struct voiceMemoTests {

    @Test func example() async throws {
        // Write your test here and use APIs like `#expect(...)` to check expected conditions.
    }

}

 

위의 소스코드가 기본적으로 생성된 것을 확인할 수 있습니다.

 

하지만 위의 코드에서 Testing 이라는 모듈과 @Test라는 에노테이션은 

 

일반적으로 Swift의 유닛테스트에서 사용하는 XCTest와는 다릅니다.

 

@Test 에노테이션은 XCTest에서는 기본적으로 사용되지 않습니다.

 

import XCTest
@testable import voiceMemo

class VoiceMemoTests: XCTestCase {

    override func setUpWithError() throws {
    }

    override func tearDownWithError() throws {
    }

    func testExample() async throws {
        let value = 2 + 2
        XCTAssertEqual(value, 4, "2 더하기 2는 4여야 합니다.")
    }
}

 

XCTest에서는 보통 해당 소스코드가 많이 사용됩니다.

 

 

private struct MemoContentInputView: View {
    @ObservedObject private var memoViewModel: MemoViewModel
    
    fileprivate init(memoViewModel: MemoViewModel){
        self.memoViewModel = memoViewModel
    }
    
    fileprivate var body: some View {
        ZStack(alignment: .topLeading) {
            TextEditor(text: $memoViewModel.memo.content)
                .font(.system(size: 20))
            
            if memoViewModel.memo.content.isEmpty {
                Text("메모를 입력하세요")
                    .font(.system(size: 16))
                    .foregroundColor(.customGray1)
                    .allowsHitTesting(false)
                    .padding(.top, 10)
                    .padding(.leading,5)
            }
        }
        .padding(.horizontal, 20)
    }
}

 

해당 예제를 한번 테스트 해 보겠습니다.

 

import XCTest

class MemoContentInputViewUITests: XCTestCase {

    var app: XCUIApplication!

    override func setUpWithError() throws {
        continueAfterFailure = false
        app = XCUIApplication()
        app.launch()
    }

    override func tearDownWithError() throws {
        app = nil
    }

    func testMemoContentInputViewPlaceholder() throws {
        let memoContentTextView = app.textViews["메모를 입력하세요"]
        
        XCTAssertTrue(memoContentTextView.exists, "플레이스홀더가 표시되지 않았습니다.")
    }

    func testMemoContentInputViewTyping() throws {
        let memoContentTextView = app.textViews["메모를 입력하세요"]
        XCTAssertTrue(memoContentTextView.exists, "메모 입력 필드가 존재해야 합니다.")
        
        memoContentTextView.tap()
        memoContentTextView.typeText("Test Memo Content")
        
        XCTAssertEqual(memoContentTextView.value as? String, "Test Memo Content", "입력된 텍스트가 올바르게 표시되지 않았습니다.")
    }
}

 

라고 적어보겠습니다.

 

 

소스코드를 보면 다이아몬드 버튼이 있습니다.

 

해당 버튼을 누르면 해당부분이 빌드가 되게 됩니다.