비동기 코드를 유닛 테스트하는 전통적인 방법으로 'XCTestExpectation' 가 있지만 굉장히 가독성이 떨어지고 난해합니다.
그래서 이번 포스트에서는 RxTest, RxBlocking에 대해 설명하려고 합니다.
Rx가 아닌 프로젝트에서는 Quick이나 Nimble이 많이 쓰이는 듯 하지만
Rx 프로젝트에서는 보통 RxTest, RxBlocking 가 많이 쓰이는 듯 합니다.
(RxNimble도 많이 쓰이는데 RxBlocking이랑 거의 사용법이 같아서 패스)
let testService = Observable.just("TEST_01")
.delay(.seconds(2), scheduler: MainScheduler.instance)
"TEST_01"란 값을 2초후에 내보내는 간단한 코드입니다.
하지만 XCTestExpectation로 테스트하려면 구독하고 fulfill 처리하고 dispose 처리하고...
이런 간단한 코드를 테스트하는데 배보다 배꼽이 더 큰 상황이 나오게 됩니다.
그럼 RxBlocking으로 처리하는 방법에 대해 알아봅시다.
let result = try? testService.toBlocking(timeout: 5).first()
XCTAssertEqual(result, "TEST_01")
겨우 2줄만에 끝나는 기적을 보실 수 있습니다!
설명할 것도 없겠지만 설명하자면
toBlocking(timeout: 5) - 비동기 작업을 결과가 올 때까지 최대 5초까지 잠깐 블락합니다.
first() - 결과 중 첫번째 인자 리턴 (First element of sequence.)
이렇게군더더기 없이 깔끔하게 테스트할 수 있습니다.
만약 테스트할 코드가 Hot Observable 이거나 데이터 스트림을 여러번 테스트할 필요가 있을 경우에는 번거롭거나 어려울 수도 있습니다.
먼저 Hot Observable 일 때 RxBlocking으로 어떻게 테스트해야할지 알아봅시다.
let testService = PublishSubject<String>()
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [self] in
testService.onNext("TEST_01")
}
let result01 = try? testService.toBlocking(timeout: 5).first()
XCTAssertEqual(result01, "TEST_01")
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [self] in
testService.onNext("TEST_02")
}
let result02 = try? testService.toBlocking(timeout: 5).first()
XCTAssertEqual(result02, "TEST_02")
// 이런식으로 쭈욱~...
이런식으로 toBlocking이 블락하는 도중에 이벤트가 방출될 수 있도록 asyncAfter로 딜레이를 주면서 이벤트를 넣어주면 됩니다.
하지만 여러 상황의 이벤트를 체크할 때 이런식으로 테스트 코드를 작성하게 되면 코드가 굉장히 길어지고 가독성이 떨어질 수도 있습니다.
let testService = PublishSubject<String>()
let scheduler = TestScheduler(initialClock: 0)
let bag = DisposeBag()
let testObs = scheduler.createHotObservable([
.next(1, "TEST_01"),
.next(2, "TEST_02"),
.next(3, "TEST_03"),
.next(4, "TEST_04")
])
testObs.bind(to: testService).disposed(by: bag)
let observer = scheduler.createObserver(String.self)
testService
.subscribe(observer)
.disposed(by: bag)
scheduler.start()
XCTAssertEqual(observer.events, [
.next(1, "TEST_01"),
.next(2, "TEST_02"),
.next(3, "TEST_03"),
.next(4, "TEST_04")
])
이런식으로 수많은 경우의 이벤트에 대해서 간편하고 보기 좋게 테스트 할 수 있습니다.
이렇게 비동기 코드를 테스트하는 방법에 대하여 알아봤습니다.
RxTest, toBlocking 만 있으면 우리 모두 간편하게 TDD 를 실천할 수 있습니다!