다른 XTest(Java, Swift, C 등 객체지향언어에서 하는 테스트)에서 하는 테스트 방법과 달리 Swift의 XCTest는 전체 테스트 클래스 (XCTestCase 서브클래싱하는 클래스)에 대해 한 번만 실행되는 라이프 사이클이 없다. 왜일까? XCTestCase의 서브 클래스의 라이프 사이클은 각 테스트 외부에서 관리하고 모든 클래스 상태(프로퍼티 등)는 테스트 메소드 간에 유지된다. 그러므로 각 테스트 메소드가 실행되는 순서에 의존할 수 없기 때문에 setup()tearDown() 메소드를 통해매 테스트마다 클래스 상태 초기화와 정리가 필요하다.
✅ Test Target organization
유닛테스트 그룹화 - 앱과 비슷하게 그룹화하자
Test Target
⌊ Cases
⌊ Group 1
⌊ Tests 1
⌊ Tests 2
⌊ Group 2
⌊ Tests
⌊ Mocks
⌊ Helper Classes
⌊ Helper Extensions
무엇을 테스트해야 할까?
가장 작은 유닛부터 테스트해야 한다.
모든 것을 테스트할 수 있당 우왕
UI 업데이트는 테스트를 어떻게 할까?
UI 자동화를 이용한 UI 테스팅은 Unit테스팅과 거리가 멀지만, 상태 제어 로직(앱 상태)을 뷰 계층에서 분리하면 유닛 테스트로 작성할 수 있다. 예를 들어, 버튼이 눌려 버튼의 텍스트가 변한다면 버튼의 텍스트가 변했다는 것을 테스트할 수 있다.
func testController_whenStartTapped_buttonLabelIsPause() {
// when
whenStartStopPauseCalled()
// then
let text = sut.startButton.title(for: .normal)
XCTAssertEqual(text, AppState.inProgress.nextStateButtonLabel)
}
위와 같이 startButton의 title을 가져올 수 있다.
func testController_whenCreated_buttonLabelIsStart() {
// given
// when
sut.viewDidLoad()
// then
let text = sut.startButton.title(for: .normal)
XCTAssertEqual(text, AppState.notStarted.nextStateButtonLabel)
}
위 코드에서 viewDidLoad를 호출해주었다. 이를 호출하지 않는다면, view가 xib에서 로드가 되지 않기 때문에, UI가 초기화되지 않는다. viewcontroller는 init할 때 view를 로드하지 않고,loadView 라이프 사이클에서 로드해준다.
정리
TDD는 앱 로직을 작성하기 이전에 테스트를 먼저 작성하는 것이다.
항상 실패하는 테스트 코드부터 시작하고, 컴파일이 되지 않는 것도 실패로 간주한다.
테스트 방법 5가지 : cmd+u / cursor + control+option+cmd+u / product -> test / navigator / 다이아몬드
UI 테스팅은 UI자동화 테스팅을 통해 편하게 할 수 있지만, UI상태를 뷰에서 분리해내면 유닛테스트로도 작성이 가능하다.
test 메소드 명명법 : test테스트하는것(sut)\_행위또는상태변경(when)\_예상하는결과
TDD App Setup
레이먼드 아저씨 책 - iOS Test-Driven Development by Tutorials 의 세번째 챕터 TDD App Setup에서 배운 내용
테스트 코드 세팅하는 방법과 테스트 방식에 대해 알아보자. 마지막엔 UI 테스팅을 Unit 테스트로 어떻게 할 수 있는지에 대해 간단히 알아보자
Setting
✅ Test Target 생성 및 test class 추가하기
cmd + n
-> Unit Test Case Class 선택✅ 테스트 방법
cmd + u
)control + option + cmd + u
✅ 테스트 모듈 import하기
앱 타겟은 프레임워크가 아니지만, 모듈이기 떄문에 test 타겟에서 프레임워크처럼 임포트할 수 있다.
모듈이 다르기 때문에 앱 타겟에서 public 접근지정자를 붙여야한다. 즉 접근레벨을 한단계 올려야한다. 하지만 이는 swift type safetry의 이점을 챙길 수 없게된다. 이를 해결하는 방식에는 두가지가 있다.
✅ 테스트 명명법
testAppModel_whenStarted_isInInProgressState
test
로 시작해야한다.AppModel
: 테스트하고 있는 시스템 (system under test = sut)whenStarted
: 테스트 상태, 혹은 행위 (when)에 해당iInInProgressState
: when 이후에 벌어진 sut의 상태, (결과)✅ XCTestCase
다른 XTest(Java, Swift, C 등 객체지향언어에서 하는 테스트)에서 하는 테스트 방법과 달리 Swift의 XCTest는 전체 테스트 클래스 (XCTestCase 서브클래싱하는 클래스)에 대해 한 번만 실행되는 라이프 사이클이 없다. 왜일까? XCTestCase의 서브 클래스의 라이프 사이클은 각 테스트 외부에서 관리하고 모든 클래스 상태(프로퍼티 등)는 테스트 메소드 간에 유지된다. 그러므로 각 테스트 메소드가 실행되는 순서에 의존할 수 없기 때문에
setup()
tearDown()
메소드를 통해매 테스트마다 클래스 상태 초기화와 정리가 필요하다.✅ Test Target organization
유닛테스트 그룹화 - 앱과 비슷하게 그룹화하자
무엇을 테스트해야 할까?
UI 업데이트는 테스트를 어떻게 할까?
UI 자동화를 이용한 UI 테스팅은 Unit테스팅과 거리가 멀지만, 상태 제어 로직(앱 상태)을 뷰 계층에서 분리하면 유닛 테스트로 작성할 수 있다. 예를 들어, 버튼이 눌려 버튼의 텍스트가 변한다면 버튼의 텍스트가 변했다는 것을 테스트할 수 있다.
위와 같이 startButton의 title을 가져올 수 있다.
위 코드에서 viewDidLoad를 호출해주었다. 이를 호출하지 않는다면, view가 xib에서 로드가 되지 않기 때문에, UI가 초기화되지 않는다. viewcontroller는 init할 때 view를 로드하지 않고,
loadView
라이프 사이클에서 로드해준다.정리
TDD는 앱 로직을 작성하기 이전에 테스트를 먼저 작성하는 것이다.
항상 실패하는 테스트 코드부터 시작하고, 컴파일이 되지 않는 것도 실패로 간주한다.
테스트 방법 5가지 : cmd+u / cursor + control+option+cmd+u / product -> test / navigator / 다이아몬드
UI 테스팅은 UI자동화 테스팅을 통해 편하게 할 수 있지만, UI상태를 뷰에서 분리해내면 유닛테스트로도 작성이 가능하다.
test 메소드 명명법 :
test테스트하는것(sut)\_행위또는상태변경(when)\_예상하는결과
테스트해야하는 요소는 가장 작은 것부터 진행한다.
뷰를 테스트할 때 vc일 경우 라이프사이클을 알아야한다.
사용한 테스트 코드