[iOS] XCode에서 Unit Test 사용해보기
오늘은 간단한 예제를 통해서 test code를 작성해볼 것이다!
UITest도 있지만 오늘은 Unit test를 한번 해보았다.
기본 UI는 저번에 구현했었던 프로필과 이름 바꾸는 예제를 활용했다
XCode에서 unit test를 하기 위해선 XCode에서 지원해주는 XCTest라는 프레임워크를 알아야 한다.
XCTest
xcode에서 XCTest를 활용해 Unit Test를 실행하여 테스트코드를 작성할 수 있다.
XCTest는 그중에서도 Xcode 프로젝트안에서 Unit Test, UI Test, 성능 테스트를 할 수 있는 프레임워크다.
애플 공식문서에 들어가보면 사용방법을 친절하게 알려주고 있다.
class TableValidationTests: XCTestCase {
/// Tests that a new table instance has zero rows and columns.
func testEmptyTableRowAndColumnCount() {
let table = Table()
XCTAssertEqual(table.rowCount, 0, "Row count was not zero.")
XCTAssertEqual(table.columnCount, 0, "Column count was not zero.")
}
}
제공해주는 메서드들도 몇가지 있고 찾아보면 금방 어떻게 작성해야할 지 감이 올 것이다!
파일에 추가하고 실행하는 과정은 아래 블로그를 참고하였다!
unit test를 처음에 실행시키면 아래와 같은 코드가 담긴 파일에 제공된다.
이 안에서 코드를 작성해주면 된다
import XCTest
final class example: XCTestCase {
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
func testExample() throws {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
// Any test you write for XCTest can be annotated as throws and async.
// Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
// Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
}
func testPerformanceExample() throws {
// This is an example of a performance test case.
measure {
// Put the code you want to measure the time of here.
}
}
}
- setUpWithError() : 초기화코드를 작성하는 함수로, 클래스의 각 테스트 메소드가 호출되기 전에 호출되는 함수
- tearDownWithError() : 해체 코드를 작성하는 함수로, 클래스의 각 테스트 메서드를 호출한 후 호출되는 함수
- testExample() : test case를 작성하는 함수로, 테스트가 올바른 결과를 생성하는지 확인하는 함수
- testPerformanceExample() : 성능 테스트 케이스를 작성하는 함수로 시간을 측정하는 코드를 작성하는 함수
그럼 이제 예제에 적용해보자
예제에 적용해볼 UI는 아래와 같다.
사용자 프로필 사진을 받고, 사용자 이름을 받은 후 저장을 눌러주면 저장되는 간단한 기능이다.
UnitTest Code
testcode는 위에 코드와 같이 작성해보았는데, 몇가지의 조건이 있었다.
- test를 진행할 함수에는 꼭 test를 앞에 붙이고 함수명을 만들어주어야 한다.
- test를 진행할 함수가 있는 모듈은 @testable import 로 선언해주어야 한다.
그럼 test code의 함수 내부 동작을 알아보도록 하자
setUpWithError()
override func setUpWithError() throws {
viewModel = ProfileViewModel()
}
- test메서드가 실행되기 전에 뷰모델의 새로운 인스턴스를 생성하여 넘겨주고 있다.
tearDownWithError()
override func tearDownWithError() throws {
viewModel = nil
}
- viewModel에 nil값을 줘서 값이 없다는 것을 전달하고, 메모리에서 해제하도록 한다.
testProfileNameChange()
func testProfileNameChange() throws {
viewModel.name = "yanni"
XCTAssertEqual(viewModel.name, "yanni", "프로필 이름이 정확하게 변경되어야 합니다.")
}
- viewModel의 name 속성을 yanni로 설정하고 설정된 값이 yanni가 맞는지 XCTAssertEqual을 통해 확인하고 있다.
- 값이 맞지 않다면 콘솔창에 "프로필 이름이 정확하게 변경되어야 합니다."라는 문구가 뜨고 실패했음을 알려준다.
testProfileSave()
func testProfileSave() throws {
XCTAssertTrue(viewModel.saveProfile(), "프로필 저장에 실패하면 안 됩니다.")
}
- viewModel의 프로필을 저장하는 saveProfile 메서드를 호출하여 저장됐는지 XCTAssertTrue를 통해 결과가 true인지 확인한다.
- 만약 false일 경우 콘솔창에 "프로필 저장에 실패하면 안 됩니다."라는 문구가 뜬다.
testPerformanceExample()
func testPerformanceExample() throws {
measure {
_ = viewModel.saveProfile()
}
}
- 성능을 테스트하는 코드를 작성했다. 프로필 정보가 담긴 정보를 저장하는 메서드의 성능을 평가한다.
전체 코드
import XCTest
@testable import ChangeMyProfile
final class UnitTests: XCTestCase {
var viewModel: ProfileViewModel!
override func setUpWithError() throws {
viewModel = ProfileViewModel()
}
override func tearDownWithError() throws {
viewModel = nil
}
func testProfileNameChange() throws {
viewModel.name = "yanni"
XCTAssertEqual(viewModel.name, "yanni", "프로필 이름이 정확하게 변경되어야 합니다.")
}
func testProfileSave() throws {
XCTAssertTrue(viewModel.saveProfile(), "프로필 저장에 실패하면 안 됩니다.")
}
func testPerformanceExample() throws {
measure {
_ = viewModel.saveProfile()
}
}
}
test code에 성공하면 초록색 체크 표시가 뜬다!
느낀점
테스트 코드에 대해 알기 전에는 기본 UI + 기능 연결 + api 연결만 해도 벅찬데 테스트코드까지 작성해야 한다고??
너무 시간을 많이 잡아먹지 않나? 라는 생각이 들었다. 하지만 이번 예제에 쉽게라도 적용해보니 작성하기까지는 어렵고 고려해야 될 것도 많은데
정말 편하겠다 .. 라는 생각이 들었다. 프로젝트 규모가 커지면 커질수록 놓치는 부분도 많고 미처 고려하지 못한 부분들도 많은데 이럴때 테스트 케이스를 통해 오류를 잡아내고, 설계를 다시 하는 실수를 줄일 수 있다는 점이 매력적이였다.
이렇게 또 하나 배워가는 하루~..