안녕하세요, 이번 포스트는 RxSwift 코드 테스트에 대한 이야기 입니다.
앱을 MVVM으로 구성했더니 테스트에 용이한 구조가되었습니다. MVVM 아키텍처의 또 다른 이점은 코드의 테스트 용이성 증가라고 할 수 있는데요, 오늘은 특히 뷰 모델에 대한 단위 테스트를 만든 경험을 공유하고자 합니다.
RxTest 라이브러리를 이용하여 RxSwfit 연산자 및 코드에 대한 테스트를 작성해 보았습니다.
테스트를 하기 전 실제로 테스트하고 싶은 것이 무엇인지 생각해보았습니다. 뷰 처럼 테스트를 할 수 없는 부분을 제외한 비즈니스 로직을 테스트 하기로 결정했습니다.
특히 뷰 모델의 Input에 대해서 원하는 Output이 잘 나오는지 확인하는것을 목표로 했습니다.
테스트를 위해 필요한 프로퍼티를 정의해줍니다.
private var viewModel: SearchViewModel!
private var disposeBag: DisposeBag!
private var scheduler: TestScheduler!
private var input: SearchViewModel.Input!
private var output: SearchViewModel.Output!
저는 뷰 모델을 테스트 할 것이기 때문에 뷰 모델과 인풋, 아웃풋, 스케쥴러 등을 선언했습니다.
override func setUpWithError() throws {
viewModel = SearchViewModel(useCase: MockSearchUseCase(), coordinator: nil)
scheduler = TestScheduler(initialClock: 0)
disposeBag = DisposeBag()
}
setUp() 에서 각 테스트가 시작되기 전에 호출되는 프로퍼티들을 초기화 해줍니다.
override func tearDownWithError() throws {
viewModel = nil
disposeBag = nil
}
tearDown() 에서 뷰모델과 디즈포즈백의 메모리를 해제해줍니다.
func test_fetch_search_result() {
let searchResultObserver = scheduler.createObserver([LocationInfo].self)
let viewWillAppearTestableObservable = scheduler.createHotObservable([.next(10, ())])
let keywordObservable = scheduler.createHotObservable([.next(20, "seoul")])
input = SearchViewModel.Input(viewWillAppear: viewWillAppearTestableObservable.asObservable(),
searchKeyword: keywordObservable.asObservable(),
itemSelected: Observable.just(nil))
output = viewModel.transform(input: input)
output.searchResult.subscribe(searchResultObserver).disposed(by: disposeBag)
scheduler.start()
XCTAssertEqual(searchResultObserver.events, [
.next(20, [LocationInfo(
uuid: "test_id",
name: "newLocation",
businessName: "eroom",
distance: "10",
coordx: "10",
coordy: "10",
address: nil
)])
])
}
scheduler.start()
를 통해 스케줄러를 시작하고 옵저버가 이벤트를 수신합니다.
테스트를 빌드하고 실행한 후 성공여부를 확인했고, 예상한 결과와 일치하는 것 을 알 수 있었습니다.
테스트코드 작성의 이점은 코드를 다시 한번 되돌아볼 수 있다는 점입니다.
실제로 아래 사진에서 SearchViewModel에 대한 테스트 진행 중 더 이상 쓰이지 않는 코드를 발견해서 리팩토링 할 수 있었습니다.
엑스코드 테스트에서 제공하는 코드 커버리지 확인 기능을 통해
커버가 안 된 부분을 확인하고
새로운 테스트를 추가 작성했습니다.
화면 전환 처럼 테스트 코드로 확인할 수 없는 부분을 제외한 모든 코드에 대해 테스트를 마쳤습니다.
이렇게 유닛 테스트를 통해 개발한것이 제대로 작동하고 있는지 확인해보았습니다.
비즈니스 로직에서 뷰 라이프 사이클을 분리하였더니 뷰 모델을 매우 간단하게 테스트 할 수 있었습니다.
RxTest도 처음이고 단위테스트를 하는것도 쉽지 않았지만, 유닛테스트 작성을 통해 사용자가 버그에 최소한으로 노출될 수 있도록 한 점이 뿌듯하네요:)