[ReactorKit] ReactorKit 공부하기 #2
ReactorKit 공부하기 #2
📌 해당 문서는 ReactorKit 3.2.0을 기준으로 하고 있습니다.
ReactorKit은 SPM을 지원하지 않습니다.
해당 프로젝트를 위해 RxTest, RxBlocking을 추가적으로 사용하였습니다.
코드 파일은 글 제일 하단에서 확인하실 수 있습니다.
이번에는 ReactorKit 테스트에 대해서 알아볼 예정이다.
한 이틀을 환경문제로 삽질을 했는데, 그 해결법을 여기에 담고 있다...
✅ RxTest는 꼭 Tests쪽으로 타겟을 잡아주세요!
그렇지 않으면 앱이 죽습니다 ㅠ
✅ 1편 포스팅 코드를 그대로 사용했습니다.
ReactorKit의 경우에는 테스트를 위한 함수가 내장되어 있다. 손쉽게 view와 reacotr 둘 다 테스트 할 수 있다!!
그렇다면 무엇을 테스트 해야할까?
- View
- Action :: 주어진 유저의 상호작용에 따라 적절한 action이 reactor로 보내지는가?
- State :: 주어진 state에서 view의 변수가 적절하게 set(저장) 되는가?
- Reactor
- State :: action에 따라 state가 적절하게 변경되었는가?
총 3가지 부분을 테스트하면 된다.
테스트 코드 작성과 관련해서는 다른 분 블로그의 댓글로 소통을 했었는데, 그 부분이 궁금하다면 글 제일 하단의 링크를 첨부할테니, 그 부분의 댓글을 확인하기!
✅ 리액터킷 테스트코드
//
// ReactorKitPracticeTests.swift
// ReactorKitPracticeTests
//
// Created by Hamlit Jason on 2022/07/23.
//
import XCTest
@testable import ReactorKitPractice
import RxTest
import RxSwift
class ReactorKitPracticeTests: XCTestCase {
override func setUp() {
}
override func tearDownWithError() throws { }
// MARK: - View -> Reactor
// View에서 Reactor Action을 잘 넘기는지 테스트
func test_Action_View_to_Reactor() {
// given
let reactor = CounterViewReactor()
let viewController = CounterViewController()
reactor.isStubEnabled = true
viewController.reactor = reactor
// when
viewController.increaseButton.sendActions(for: .touchUpInside)
XCTAssertEqual(reactor.stub.actions.last, .increase)
// then
viewController.decreaseButton.sendActions(for: .touchUpInside)
XCTAssertEqual(reactor.stub.actions.last, .decrease)
}
// MARK: - Reactor -> View
// Reactor에서 변경된 상태(State)가 View에도 정상적으로 반영되는지 확인.
func test_State_Reactor_to_View() {
// given
let reactor = CounterViewReactor()
let viewController = CounterViewController()
reactor.isStubEnabled = true
viewController.reactor = reactor
// when
reactor.stub.state.value = CounterViewReactor.State(value: 0, isLoading: true)
// then
XCTAssertEqual(viewController.loadingIndicator.isAnimating, true)
XCTAssertEqual(viewController.countLabel.text, "0")
}
// MARK: - Reactor
// action을 받으면 비지니스 로직(Mutation)이 잘 처리되어 State값이 기대값으로 변하는지 확인.
func test_Reactor() {
let reactor = CounterViewReactor()
let expectation = XCTestExpectation()
expectation.expectedFulfillmentCount = 1
// when
reactor.action.onNext(.increase)
// then
XCTAssertEqual(reactor.currentState.isLoading, true)
}
}
🚨 실패한 테스트코드
실패한 테스트코드입니다.
isLoading의 경우에는 false -> true(딜레이 1초) -> false로 결과가 방출되어야할 것 같은데, false -> true만 내려오고 있습니다.
딜레이 처리를 잘못한 것이 원인이 아닐까 생각하고 있으나, 현재 저의 시각으로는 문제를 해결하지 못했습니다.
해당 원인은 아시는 분은 알려주세요!
// 실패한 테스트 코드
// 작성일: 2022년 7월 25일
// 원인: delay의 문제로 보이나, 어떻게 해결할지 아직 잘 모르겠음.
// (문제 해결을 위해 시도해본 방법)
// 1. DispatchQueue를 활용
// 2. expectation 활용
func test_isLoading() {
let scheduler = TestScheduler(initialClock: 0)
let reactor = CounterViewReactor()
let disposeBag = DisposeBag()
scheduler.createHotObservable([
.next(100, .increase),
])
.subscribe(reactor.action)
.disposed(by: disposeBag)
// then
let response = scheduler.start(created: 0, subscribed: 0, disposed: 1000) {
reactor.state.map(\.isLoading)
}
XCTAssertEqual(response.events.map(\.value.element), [
false, // initial state
true, // 값 변경 .isLoading
false // 딜레이 후 isLoading
])
}
(참고)
https://ios-development.tistory.com/783?category=1021553