이전 포스팅
개요
저번 포스팅에서는 유닛테스트가 무엇인지와 어떻게 설정하는지에 대해 포스팅하였는데, 이번에는 간단한 예제를 통해 직접 Unit Test를 해볼 예정이다. 예제는 Ray Wenderlich의 강의에 있는 내용을 가져와서 사용할 것이고, 해당 예제 링크는 아래에서 확인이 가능하다.
iOS Unit Testing and UI Testing Tutorial
테스트할 클래스
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()
}
}
- 자신이 테스트할 프로젝트를 @testable 키워드와 함께 import 한다.
- 해당 테스트 클래스에서 테스트하고 싶은 클래스의 mock 객체를 선언한다.
- setUpWithError()에서 선언한 mock 객체를 초기화 시켜준다.
- tearDownWithError()에서 mock 객체를 할당 해제 시켜준다.
Check함수 테스트
BullsEyeGame 클래스에 있는 Check 함수는 Int형 파라미터인 guess에 자신이 추측한 점수를 입력하면 진짜 점수(targetValue)와 추측한 점수(guess)의 차이를 구한 뒤 100에서 그점수를 뺀 점수를 scoreTotal에 올려준다. 이 함수가 의도대로 잘 작동하는지 실험할 예정이다.
테스트 함수에 내용은 targetValue보다 크거나 작은 숫자를 입력하였을 때 정상적으로 scoreRound가 적용이 되는지 알아보는 내용이다. 테스트는 3가지 단계로 구성되어 있다.
- given
- 테스트할 값을 설정한다. 위에 함수는 targetValue보다 5 작은 숫자를 아래 함수에는 targetValue보다 5 큰 숫자를 설정하였다.
- when
- 테스트할 함수를 실행한다. BullsEyeGame 클래스내에 check 함수를 호출한다.
- then
- 1번째 파라미터 : 테스트할 대상을 지정한다.
- 2번째 파라미터 : 테스트할 대상에서 도출되어야할 값을 지정한다.
- 3번째 파라미터 : 원하는 값이 안나왔을 때 즉, 실패했을 때 나오는 메세지를 입력한다.(optional)
- 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)
재테스트 결과 정상적인 값이 나오는 것을 확인할 수 있다.
'Swift' 카테고리의 다른 글
14. UI Test (0) | 2022.12.31 |
---|---|
13. Unit Test(3) (0) | 2022.12.23 |
11. Unit Test(1) (0) | 2022.12.09 |
10. 멀티 스레딩과 GCD (0) | 2022.12.04 |
9. 프로세스와 스레드 (0) | 2022.08.25 |