[Swift] 비동기 코드 테스트하기

OQ·2022년 3월 24일
0

Swift

목록 보기
4/11
post-thumbnail

비동기 코드를 유닛 테스트하는 전통적인 방법으로 '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로 딜레이를 주면서 이벤트를 넣어주면 됩니다.
하지만 여러 상황의 이벤트를 체크할 때 이런식으로 테스트 코드를 작성하게 되면 코드가 굉장히 길어지고 가독성이 떨어질 수도 있습니다.

이런 경우에는 RxTest를 써주시는게 훨씬 간편합니다!

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 를 실천할 수 있습니다!

profile
덕업일치 iOS 개발자

0개의 댓글