728x90
728x90
SMALL
오늘은 예전부터 해야지해야지 했던 TDD를 아주 간단하게만 사용해보았다.
비동기랑 UI부분도 유닛테스트가 가능하다고 하는데 비동기는 추후 좀 더 큰 프로젝트를 진행하면서 사용해볼예정이고,
이번에는 숫자야구게임 프로젝트를 만들어서 간단히 기능 부분이나 UI부분만 Unit Test를 찍먹 해보려고한다!
코드는 Apple에서 제공하는 유닛 테스트 프레임워크인 XCTest를 이용해 작성하였다 :)
프로젝트 동작 결과화면
Github
XCTest, Unit Test 작성 전 알아보기
- TDD
- TDD란 Test Driven Development의 약자로 "테스트 주도 개발"이라는 의미이다
- "테스트 케이스 고려 > 테스트 케이스 작성 > 리팩토링"의 형식으로 진행된다
- 여기서 테스트 케이스는 독립적으로 진행될 수 있는 가장 작은 단위(Unit)로 작성한다
- 테스트 케이스 생각하기
- 가장 큰 테스트의 목표를 설정하고, 이를 기반으로 어떤 케이스들을 테스트 할 것인지 미리 생각한다
- "버튼을 누르면 출력되는 결과가 맞는지 확인한다"와 같은 독립적인 작은 기능을 하나의 테스트 단위로 설정한다
- Test 메소드 이름은?
항상 test로 시작하며 해당 메소드가 테스트하는 내용을 기반으로 이름을 설정한다
Test를 포함한 프로젝트 생성
빨간 박스의 "Include Tests"를 체크하면 자동으로 테스트가 포함된 프로젝트를 생성할 수 있다
- 상단의 마름모+체크 표시 버튼을 클릭한다
- 각 부분들을 선택하여 기능, UI 등 원하는 Unit Test를 진행할 수 있다
숫자야구 관리 클래스
class BullsandCows {
private var answer:[String] = []
private var score:[String] = []
// 정답 여부
var isCorrect:Bool {
return score == ["S", "S", "S"]
}
init() {
makeAnswer()
}
// 정답 입력
func inputAnswer(_ input:String) {
// 정답 리셋
answer.removeAll()
// 입력 값으로 정답 설정
_ = input.map{ answer.append(String($0)) }
}
// 정답 생성기
func makeAnswer() {
// 정답 리셋
answer.removeAll()
// 랜덤한 정답 생성
for _ in 0..<3 {
let randomNum = Int.random(in: 0...9)
answer.append(String(randomNum))
}
}
// 정답 확인
func checkResult(_ input:[String]) {
// score 비우기
score.removeAll()
// 정답 체크
for (i, data) in input.enumerated() {
for (j, result) in answer.enumerated() {
if data == result {
score.append(i == j ? "S" : "B")
break
}
}
if score.count-1 != i {
score.append("O")
}
}
}
// 정답 반환
func getAnswer() -> [String] {
return answer
}
// 스코어 반환
func getScore() -> [String] {
return score
}
// 스코어 출력
func printScore() -> String {
let result = score.joined(separator: " ")
return result
}
}
기능 테스트
- TDDTests.swift
final class TDDTests: XCTestCase {
// 숫자야구 게임 작동을 위한 메인 클래스
private var bullAndCows:BullsandCows!
// 초기 설정 (생성 등을 담당)
override func setUpWithError() throws {
try super.setUpWithError()
bullAndCows = BullsandCows()
}
// CleanUp
override func tearDownWithError() throws {
bullAndCows = nil
try super.tearDownWithError()
}
}
- setUpWithError() : 기능 테스트를 위해 숫자야구 게임을 관리하는 BullandCows 클래스를 생성
- tearDownWithError() : 테스트 종료 후 메모리 해제
// BullsandCows 생성 시 초기 정답 값 여부 확인
func testAnswerNotNil() {
// given, when
let answer = bullAndCows.getAnswer()
// then
XCTAssertNotEqual(answer.count, 0)
}
// SSS일 경우
func testSSS() throws {
// given, 값 설정
bullAndCows.inputAnswer("123")
bullAndCows.checkResult(["1", "2", "3"])
// when, 테스트 코드 실행
let result = bullAndCows.printScore()
// then, 예상 결과 확인
XCTAssertEqual(result, "S S S", "정답이 잘못되었습니다")
}
// OOO일 경우
func testOOO() throws {
// given, 값 설정
bullAndCows.inputAnswer("000")
bullAndCows.checkResult(["1", "2", "3"])
// when, 테스트 코드 실행
let result = bullAndCows.printScore()
// then, 예상 결과 확인
XCTAssertEqual(result, "O O O", "정답이 잘못되었습니다")
}
// BBB일 경우
func testBBB() throws {
// given, 값 설정
bullAndCows.inputAnswer("312")
bullAndCows.checkResult(["1", "2", "3"])
// when, 테스트 코드 실행
let result = bullAndCows.printScore()
// then, 예상 결과 확인
XCTAssertEqual(result, "B B B", "정답이 잘못되었습니다")
}
// SOS일 경우
func testSOS() throws {
// given, 값 설정
bullAndCows.inputAnswer("103")
bullAndCows.checkResult(["1", "2", "3"])
// when, 테스트 코드 실행
let result = bullAndCows.printScore()
// then, 예상 결과 확인
XCTAssertEqual(result, "S O S", "정답이 잘못되었습니다")
}
- testAnswerNotNil() : BullsandCows를 생성할 때 초기 정답값이 생성되도록 되어있다. 이 코드가 제대로 수행되는지 확인
- testXXX() : 정답을 설정한 후 다양한 결과가 나오도록 답을 입력하고 해당 결과가 맞게 출력되는지 테스트를 진행
UI 테스트
- TDDUITests.swift
final class TDDUITests: XCTestCase {
// 초기화 및 기본 세팅
override func setUpWithError() throws {
try super.setUpWithError()
continueAfterFailure = false
}
// CleanUp
override func tearDownWithError() throws {
try super.tearDownWithError()
}
}
- setUpWithError() : 해당 부분에서 테스트 앱을 실행하는 코드를 추가해도 무방함
- tearDownWithError() : 테스트 종료 후 해제 해야할 것들이 있다면 추가
// 숫자 입력을 위해 버튼을 클릭했을때 시트가 등장하여 숫자 버튼이 노출되는가
func testClickNumButtonAndUpSheet() throws {
// 테스트 앱 실행
let app = XCUIApplication()
app.launch()
// Num 버튼을 찾고 존재하는지 확인
let btnInput = app.buttons.firstMatch
XCTAssertTrue(btnInput.exists)
btnInput.tap() // 버튼 클릭
// sheet가 열려서 숫자 버튼들이 나오는지 확인
let btnNum = app.buttons["0"]
XCTAssertTrue(btnNum.exists, "숫자 버튼이 존재하지 않습니다")
}
// 숫자 입력 후 화면이 변경되는가
func testClickSheetAfterChange() throws {
// 테스트 앱 실행
let app = XCUIApplication()
app.launch()
// Num 버튼을 찾고 존재하는지 확인
let btnInput = app.buttons.firstMatch
XCTAssertTrue(btnInput.exists)
btnInput.tap() // 버튼 클릭
// sheet가 열려서 숫자 버튼들이 나오는지 확인
let btnZero = app.buttons["0"]
XCTAssertTrue(btnZero.exists, "숫자 버튼이 존재하지 않습니다")
btnZero.tap() // sheet에서 숫자 클릭
// 화면이 변경되었는지 확인
let btnMark = app.buttons["?"]
XCTAssertNotEqual(btnInput, btnMark, "?가 숫자로 변경되지 않았습니다")
}
- testClickNumButtonAndUpSheet() : 숫자 입력을 위해 버튼을 클릭하면 숫자 입력 시트가 올라오는지 확인
- testClickSheetAfterChange() : 숫자 입력 시트에서 숫자를 입력하면 버튼이 변경되는지 확인
테스트 실행
해당 클래스 선언부 옆의 마름모 버튼을 클릭하면 테스트를 실행할 수 있다
UITest의 경우 시뮬레이터가 실행되며 직접 UI가 변경되는 모습을 볼 수 있다
참고사이트
728x90
728x90
LIST
'EXPERIENCE > iOS' 카테고리의 다른 글
[Xcode/iOS] 간단한 예제로 Protocol 구현해보기 (with. SwiftUI) (0) | 2023.04.06 |
---|---|
iOS/Swift 직무를 위한 면접 질문리스트(with. ARC, GCD, Dispatch Queue, 접근제어, 메모리 참조) (1) | 2023.02.27 |
[Xcode/iOS] SwiftUI 웹뷰(WebView)와 사파리(Safari)로 페이지 화면가져오는 코드 구현해보기 (with. Safari URL 변경 안될 때) (0) | 2023.02.05 |
[Xcode/iOS] SwiftUI 구글(Google)로그인 구현하고 정보 가져오기 (0) | 2023.02.01 |
[Xcode/iOS] CocoaPods pod init, Podfile 생성 시 Error 해결방법 (0) | 2023.01.26 |