Notice
Recent Posts
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- 카카오맵클론
- storekit2
- 리팩터링
- RC
- firestore
- css학습
- hackerrank
- five lines of cdde
- algorithm
- SWIFT
- 프로그래머스
- Di
- RxSwift
- ARC
- TDD
- 클린코드
- IOS
- Swift디자인패턴
- AutoLayout
- alamofire
- mrc
- 코딩테스트입문
- UIKit
- 앱의생명주기
- ios면접
- firebase
- unittest
- Safari Inspector
- Swift코딩테스트
- five lines of code
Archives
- Today
- Total
샘성의 iOS 개발 일지
ReactorKit Unit Test하기 본문
728x90
1. 테스트 내용 선정
오늘 테스트하고자 하는 것은 하단의 3가지이다.
- View의 Action이 Reactor에게 잘 전달 되었는지 확인
- Reactor가 전달받은 Action에 대한 Mutation을 잘 작동시켰는지 State 상태 확인
- Reactor의 State를 View가 잘 구독하고 있는지 확인
2. 테스트 방식
테스트 방식은
- SUT 설정
- 테스트 시나리오 작성 및 실행 (GWT 형식)
순서로 진행될 것이다.
(만약 이 내용이 이해가지 않는다면 하단의 게시글 참고 부탁드립니다.)
[XCTest] Unit Test작성하기 (feat. RxSwift)
1. Unit Test란? 가장 작은 단위의 테스트로, 앱의 동작을 위해 작성한 코드(기능) 1개가 의도대로 잘 작동하는지 검증하는 것을 목적으로 둔다. 2. Unit Test의 필요성? 물론, Unit Test를 하지 않고 시뮬
iossammy.tistory.com
3. 테스트 대상 선정 및 시나리오 작성
우선, View와 Reactor간의 상태 전달이 잘 일어나는지를 확인하는 것이므로 테스트 대상은 ViewController로 설정하게 된다.
let sut: ViewController()
하단의 3가지를 테스트할 것이기에 시나리오를 최소 3가지 이상은 작성하게 된다.
- View의 Action이 Reactor에게 잘 전달 되었는지 확인
- Reactor가 전달받은 Action에 대한 Mutation을 잘 작동시켰는지 State 상태 확인
- Reactor의 State를 View가 잘 구독하고 있는지 확인
필자는 depositButton, withdrawButton에 대한 액션이 잘 작동하는지를 확인해야하기에
View의 Action 전달에 대한 2가지 시나리오, Mutation에 대한 State 변화 확인을 위한 2가지 시나리오, 그리고 State에 대한 View의 상태 변경 여부에 대한 1가지 시나리오 >> 이렇게 총 5가지 시나리오를 작성할 것이다.
그리고 각 시나리오에 대한 코드는 하단의 코드와 같다.
* View -> Reactor Action Test
func testAction_whenDidTapDepositButton_amount300_sendActions() {
// Given
let reactor = TransactionReactor(data: mockData)
reactor.isStubEnabled = true
sut.reactor = reactor
sut.amonutTextField.text = "300"
// When
sut.depositButton.sendActions(for: .touchUpInside)
// Then
>> reactor에서 마지막으로 동작하는 액션이 오른쪽과 같은지 확인
XCTAssertEqual(reactor.stub.actions.last, .deposit(300))
}
func testAction_whenDidTapWithdrawButton_amount300_sendActions() {
// Given
let reactor = TransactionReactor(data: mockData)
reactor.isStubEnabled = true
sut.reactor = reactor
sut.amonutTextField.text = "300"
// When
sut.withdrawButton.sendActions(for: .touchUpInside)
// Then
>> reactor에서 마지막으로 동작하는 액션이 오른쪽과 같은지 확인
XCTAssertEqual(reactor.stub.actions.last, .withdraw(300))
}
* Reactor (State status about Mutation) Test
func testStateStatus_whenDeposit300_thenBalanceStateIs300() {
// Given
let reactor = TransactionReactor(data: mockData)
// When
reactor.action.onNext(.deposit(300))
// Then
>> 변화한 reactor의 State가 예상값과 일치한지 확인
XCTAssertEqual(reactor.currentState.currentBalance, 300)
}
func testStateStatus_whenWIthdraw300_thenBalanceStateIsMinus300() {
// Given
let reactor = TransactionReactor(data: mockData)
// When
reactor.action.onNext(.withdraw(300))
// Then
>> 변화한 reactor의 State가 예상값과 일치한지 확인
XCTAssertEqual(reactor.currentState.currentBalance, -300)
}
* Reactor -> View (View observing State Value) Test
func testState_whenStateValueIs300_thenTextFieldTextIs300() {
// Given
let reactor = TransactionReactor(data: mockData)
reactor.isStubEnabled = true
sut.reactor = reactor
// When
reactor.stub.state.value = .init(currentBalance: 300)
// Then
>> State값이 제대로 바인딩 되는지 확인
let testBalance = sut.balanceView.balanceLabel.text
XCTAssertEqual(testBalance, "300")
}
4. 전체 코드
import XCTest
@testable import RxSwift_Tutorial_6
import ReactorKit
final class RxSwift_Tutorial_6Tests: XCTestCase {
private var sut: TransactionViewController!
private var mockData = MockData(account: BankAccount(balance: 0,
history: []))
override func setUp() {
sut = TransactionViewController()
}
override func tearDown() {
sut = nil
}
// MARK: - View -> Reactor Action Test
func testAction_whenDidTapDepositButton_amount300_sendActions() {
// Given
let reactor = TransactionReactor(data: mockData)
reactor.isStubEnabled = true
sut.reactor = reactor
sut.amonutTextField.text = "300"
// When
sut.depositButton.sendActions(for: .touchUpInside)
// Then
XCTAssertEqual(reactor.stub.actions.last, .deposit(300))
}
func testAction_whenDidTapWithdrawButton_amount300_sendActions() {
// Given
let reactor = TransactionReactor(data: mockData)
reactor.isStubEnabled = true
sut.reactor = reactor
sut.amonutTextField.text = "300"
// When
sut.withdrawButton.sendActions(for: .touchUpInside)
// Then
XCTAssertEqual(reactor.stub.actions.last, .withdraw(300))
}
// MARK: - Reactor (State status about Mutation) Test
func testStateStatus_whenDeposit300_thenBalanceStateIs300() {
// Given
let reactor = TransactionReactor(data: mockData)
// When
reactor.action.onNext(.deposit(300))
// Then
XCTAssertEqual(reactor.currentState.currentBalance, 300)
}
func testStateStatus_whenWIthdraw300_thenBalanceStateIsMinus300() {
// Given
let reactor = TransactionReactor(data: mockData)
// When
reactor.action.onNext(.withdraw(300))
// Then
XCTAssertEqual(reactor.currentState.currentBalance, -300)
}
// MARK: - Reactor -> View (View observing State Value) Test
func testState_whenStateValueIs300_thenTextFieldTextIs300() {
// Given
let reactor = TransactionReactor(data: mockData)
reactor.isStubEnabled = true
sut.reactor = reactor
// When
reactor.stub.state.value = .init(currentBalance: 300)
// Then
let testBalance = sut.balanceView.balanceLabel.text
XCTAssertEqual(testBalance, "300")
}
}
728x90
'iOS > Reactive Swift' 카테고리의 다른 글
ReactorKit을 MVVM에 넣어보기 (0) | 2023.07.02 |
---|---|
[XCTest] Unit Test작성하기 (feat. RxSwift) (0) | 2023.07.01 |
네이버 검색 API 사용하기 (feat. RxSwift, Alamofire) (0) | 2023.06.23 |