[Test] 유닛 테스트 ( Unit Test ) 기본

안녕하세요🐶

빈지식 채우기의 비니🙋🏻‍♂️입니다.

.

어떠한 A 라는 기능을 개발하였고, 

해당 기능을 테스트 하기 위해서 프로젝트 Run 을 하는 경우가 많습니다.

이 방법으로도 충분히 테스트가 가능하지만!

시간도 오래 걸릴 뿐더러 생산성을 저하시킬 수 있기 때문에

우리는 유닛 테스트 ( Unit Test ) 라는 것을 사용할 수 있습니다.


1. FIRST 원칙

유닛 테스트는 아래와 같이 FIRST 원칙을 지켜야 합니다.

 

속도 ( Fast )

느린 테스트는 개발자가 코드를 수정하고 결과를 확인하기까지 시간이 걸려 생산성을 저하시킨다.

따라서 유닛 테스트에서는 빠른 속도로 테스트를 수행할 수 있도록 설계해야한다.

 

독립적 ( Independent / Isolated )

유닛 테스트는 각각의 테스트가 독립적으로 실행될 수 있어야 합니다.

이러한 방식으로 작성된 유닛 테스트는 코드 변경에 대해 신속하게 대응을 할 수 있습니다.

 

반복적 ( Repeatable )

유닛 테스트는 반복적으로 실행될 수 있어야 합니다.

동일한 입력값에 대해서는 항상 동일한 결과를 보여야 합니다.

이러한 특징은 테스트의 신뢰성을 높일 수 있습니다.

 

자동화 ( Self-Automation )

수동으로 테스트 하는 것보다 자동화된 테스트를 수행하면 시간과 비용을 절약할 수 있습니다.

또한 자동화 테스트는 개발자가 코드를 변경하거나 기능을 추가할 때마다 쉽게 실행할 수 있어서 버그를 손쉽게 찾을 수 있습니다.

 

시점 ( Timely )

코드가 수정되어도 다른 부분에 영향을 미치지 않는지 확인할 수 있는 시점에 테스트를 실행해야 합니다.

코드 수정 후 변경 사항을 더욱 빠르게 확인할 수 있습니다.


2. 생성 방법

유닛 테스트 생성 방법은 크게 두가지가 있습니다.

2-1. 프로젝트 생성 시

프로젝트 생성 시 테스트 생성 방법

  • Include Tests 를 체크 후 프로젝트 생성

2-2. 프로젝트 생성 이후

프로젝트 생성 이후 테스트 생성 방법

  1. 좌측 네비게이션에서 상위 프로젝트 클릭 > Editor > Add Target 
  2. Unit Test 검색 후 생성
  3. 생성된 Test 폴더 확인

Unit Test 코드

 

기본 테스트 코드 생성 확인 완료 


3. 간단 설명


XCTest 란 실제 유닛 테스트를 할 수 있게 도와주는 프레임워크 입니다.

또한 각각의 테스트가 서로 영향을 미치지 않도록 ( 독립성 ) 메서드를 통해 테스트를 도와줍니다.


XCTest 프로세스

위 XCTest 프로세스를 기반으로,

아래 작업 간단한 예시를 작성을 해보았습니다.

import XCTest

final class RxSwift_Study_1Test2: XCTestCase {

    // 타입 메서드로 시작 전 딱 한 번만 호출됩니다.
    // 모든 테스트 메서드에서 실행 전 정의하거나 초기화할 작업에 대해 구현합니다.
    override class func setUp() {
        super.setUp()
        
        print("전체 테스트 시작!")
    }
    
    // 각 테스트 메서드가 실행되기 전에 실행됩니다.
    // 각각 테스트 메서드에서 사용될 것들에 대해 초기화 하는 작업에 대해 구현합니다.
    override func setUpWithError() throws {
        try super.setUpWithError()
        
        print("테스트1 시작!(setUpWithError)")
    }
    
    // setUpWithError 와 동일하지만 다른 점은 실행 도중 발생한 에러에 대해 처리할 수 있는 점입니다.
    override func setUp() {
        super.setUp()
        
        print("테스트1 시작!(setUp)")
    }
    
    // 실제 테스트에서 사용될 메서드 블럭입니다.
    func testMethod() throws {
        print("testMethod() 호출")
        
        // testMethod()가 종료될 때 실행되는 코드 블럭입니다.
        // 먼저 선언된 블럭이 나중에 실행되는 LIFO 구조입니다.
        addTeardownBlock {
            print("addTearDownBlock 호출")
        }
    }
    
    // 각각의 테스트가 종요되고 나서 호출됩니다.
    // 메서드 수행 후 정리하는 작업을 오버라이드하여 구현합니다.
    override func tearDown() {
        super.tearDown()
        
        print("테스트1 종료(tearDown)")
    }
    
    // tearDown() 메서드와 마찬가지로 각각의 테스트 종료 후에 호출 됩니다.
    // 다른 점은 해당 메서드는 실행 도중 발생한 에러에 대해 처리가 가능합니다.
    override func tearDownWithError() throws {
        try super.tearDownWithError()
        
        print("테스트1 종료(tearDownWithError)")
    }
    
    // 타입 메서드로 모든 테스트가 종료되고 딱 한번만 호출됩니다.
    // 모든 테스트를 마치고 정리해야 할 작업에 대해 구현합니다.
    override class func tearDown() {
        super.tearDown()
        
        print("전체 테스트 종료!")
    }
    
}

 

테스트를 사용할 때 사용하는 메서드는 다음과 같습니다.

  • class func setUp()
    • 타입 메서드로 테스트 시작 전 한번만 호출됩니다.
    • 모든 테스트 메서드에서 실행 전 정의해야할 것이나 초기화할 작업에 대해 구현합니다.

 

  • func setUpWithError()
    • 각 테스트 메서드가 실행되기 전 실행됩니다.
    • 각각의 테스트에서 사용되는 값에 대한 초기화가 구현됩니다.
    • func setUp() 과 동일한 기능을 가지지만, 다른 점은 해당 메서드는 실행 중간에 발생하는 에러를 처리할 수 있습니다.

 

  • func setUp()
    • setUpWithError() 와 동일한 기능을 가집니다.

 

  • func testMethod() & addTearDownBlock(_:)
    • 실질적은 테스트를 수행하는 메서드입니다.
    • 테스트 메서드 이름은 자유롭게 지을 수 있습니다.
    • addTearDownBlock(_:) 의 경우 testMethod() 가 종료될 때 실행됩니다.
    • addTearDownBlock(_:) 의 경우 먼저 선언된 것이 나중에 실행되는 LIFO 구조로 호출됩니다.

 

  • func tearDown()
    • 각각의 메서드가 종료되고 나서 실행됩니다.
    • 각각의 테스트가 진행되고 정리하는 작업에 대해 구현합니다.

 

  • func tearDownWithError()
    • tearDown() 과 동일한 기능을 가졌습니다.
    • 다른 점은 해당 메서드의 경우 실행 도중에 발생하는 에러에 대해 처리가 가능합니다.

 

  • class func tearDown()
    • 타입 메서드로 모든 테스트가 종료되고 딱 한 번만 호출됩니다.
    • 모든 테스트를 마치고 정리해야할 작업을 구현합니다.

이상으로 간단하게 유닛 테스트 ( Unit Test ) 의 기본에 대해 알아보았습니다.합니다.ㅇ


참고

'iOS📱 > 유틸' 카테고리의 다른 글

[Test] 유닛 테스트 ( Unit Test ) 간단 예제  (0) 2024.02.07