Swift

12. Unit Test(2)

Daesiker 2022. 12. 16. 11:18
반응형

이전 포스팅

 

11. Unit Test(1)

Unit Test란? 유닛 테스트(unit test)는 컴퓨터 프로그래밍에서 소스 코드의 특정 모듈이 의도된 대로 정확히 작동하는지 검증하는 절차이다. 즉, 모든 함수와 메서드에 대한 테스트 케이스를 작성하

daesiker.tistory.com

개요

저번 포스팅에서는 유닛테스트가 무엇인지와 어떻게 설정하는지에 대해 포스팅하였는데, 이번에는 간단한 예제를 통해 직접 Unit Test를 해볼 예정이다. 예제는 Ray Wenderlich의 강의에 있는 내용을 가져와서 사용할 것이고, 해당 예제 링크는 아래에서 확인이 가능하다.

iOS Unit Testing and UI Testing Tutorial

 

iOS Unit Testing and UI Testing Tutorial

Learn how to add unit tests and UI tests to your iOS apps, and how you can check on your code coverage.

www.kodeco.com

테스트할 클래스

BullsEyeGame란 클래스를 테스트할 예정이고 해당 클래스안에 있는 2개의 함수를 테스트할 예정이다.

  • func check(guess: Int) → Int
  • func getRandomNumber(completion: @escaping (Int) -> Void)
class BullsEyeGame {
    var round = 0
    let startValue = 50
    var targetValue = 50
    var scoreRound = 0
    var scoreTotal = 0
    
    var urlSession: URLSessionProtocol = URLSession.shared
    
    init() {
        startNewGame()
    }
    
    func startNewGame() {
        round = 1
        scoreTotal = 0
    }
    
    func startNewRound(completion: @escaping () -> Void) {
        round += 1
        scoreRound = 0
        getRandomNumber { newTarget in
            self.targetValue = newTarget
            DispatchQueue.main.async {
                completion()
            }
        }
    }
    
    @discardableResult
    func check(guess: Int) -> Int {
        
        let difference = guess - targetValue
        scoreRound = 100 - difference
        scoreTotal += scoreRound
        return difference
        
    }
    
    func getRandomNumber(completion: @escaping (Int) -> Void) {
        guard let url = URL(string: "<https://www.randomnumberapi.com/api/v1.0/random?min=0&max=100&count=1>") else {
            return
        }
        
        let task = urlSession.dataTask(with: url) { data, _, error in
            do {
                guard
                    let data = data,
                    error == nil,
                    let newTarget = try JSONDecoder().decode([Int].self, from: data).first
                else {
                    print("에러가 발생했습니다.", error?.localizedDescription ?? "")
                    return
                }
                completion(newTarget)
            } catch {
                print("Decoding of random numbers failed.")
            }
        }
        task.resume()
    }
}

Unit Test 초기설정

import XCTest
@testable import UnitTestExample //1번

final class UnitTestExampleTests: XCTestCase {
    
    var sut: BullsEyeGame! //2번
    
    override func setUpWithError() throws {
        //3번
        try super.setUpWithError()
        sut = BullsEyeGame()
        
    }
    
    override func tearDownWithError() throws {
        //4번
        sut = nil
        try super.tearDownWithError()
        
    }
    
}
  1. 자신이 테스트할 프로젝트를 @testable 키워드와 함께 import 한다.
  2. 해당 테스트 클래스에서 테스트하고 싶은 클래스의 mock 객체를 선언한다.
  3. setUpWithError()에서 선언한 mock 객체를 초기화 시켜준다.
  4. tearDownWithError()에서 mock 객체를 할당 해제 시켜준다.

Check함수 테스트

BullsEyeGame 클래스에 있는 Check 함수는 Int형 파라미터인 guess에 자신이 추측한 점수를 입력하면 진짜 점수(targetValue)와 추측한 점수(guess)의 차이를 구한 뒤 100에서 그점수를 뺀 점수를 scoreTotal에 올려준다. 이 함수가 의도대로 잘 작동하는지 실험할 예정이다.

테스트 함수에 내용은 targetValue보다 크거나 작은 숫자를 입력하였을 때 정상적으로 scoreRound가 적용이 되는지 알아보는 내용이다. 테스트는 3가지 단계로 구성되어 있다.

  1. given
  2. 테스트할 값을 설정한다. 위에 함수는 targetValue보다 5 작은 숫자를 아래 함수에는 targetValue보다 5 큰 숫자를 설정하였다.
  3. when
  4. 테스트할 함수를 실행한다. BullsEyeGame 클래스내에 check 함수를 호출한다.
  5. then
    • 1번째 파라미터 : 테스트할 대상을 지정한다.
    • 2번째 파라미터 : 테스트할 대상에서 도출되어야할 값을 지정한다.
    • 3번째 파라미터 : 원하는 값이 안나왔을 때 즉, 실패했을 때 나오는 메세지를 입력한다.(optional)
  6. XCTAssertEqual를 통해 해당 테스트에서 원하는 값이 나왔는지 확인한다.

func 옆에 마름모 버튼을 클릭하면 해당 함수를 개별적으로 테스트가 가능하다.

‼️XCTAssertEqual 말고도 XCTAssertNotEqual, XCTAssertNill, XCTAssertLessThen 등 많은 함수가 존재하는데 거의 대부분이 함수명을 보고 유추할 수 있고, apple document에도 자세히 설명이 돼있다.

테스트 결과

두 함수다 targetValue랑 5가 차이나기 때문에 기존 scoreRound 100에서 5를 뺀 95가 나와야 하는데, 위에 함수는 95가 아닌 105가 나온다는 것을 확인할 수 있다.

check 함수 확인

@discardableResult
    func check(guess: Int) -> Int {
        
        let difference = guess - targetValue
        scoreRound = 100 - difference
        scoreTotal += scoreRound
        return difference
        
    }

해당 코드를 살펴보면 guess에서 targetValue를 뺀 값인 difference를 구한뒤 100에서 difference를 뺀 값을 scoreRound에 대입한다.

즉, 음수가 나오면 100에서 오히려 difference가 더해지는것을 확인할 수 있다. 그래서 difference를 구할 때 abs함수로 감싸주어서 절대값을 적용시키면 정상적으로 작동이 될꺼같다.

let difference = abs(guess - targetValue)

재테스트 결과 정상적인 값이 나오는 것을 확인할 수 있다.

반응형