Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RxTest入門

tasanobu
November 17, 2016

 RxTest入門

第3回RxSwift勉強会で発表した資料です。
https://connpass.com/event/41478/

tasanobu

November 17, 2016
Tweet

More Decks by tasanobu

Other Decks in Technology

Transcript

  1. RxTest ͱ͸ • RxSwift ϨϙδτϦͰఏڙ͞Ε͍ͯΔςετϑϨʔϜ ϫʔΫ • RxSwift ࣗମͷςετʹར༻͞Ε͍ͯΔ •

    Cocoapods ͔ΒΠϯετʔϧՄೳ target 'RxTest-SampleTests' do pod 'RxTest', '~> 3.0' pod 'RxSwift', '~> 3.0' pod 'RxCocoa', '~> 3.0' end
  2. RxTest ͷओཁͳΫϥε • TestScheduler • RxTestͷத৺తͳΫϥε • ࣮࣌ؒͱ͸੾Γ཭͞ΕͨԾ૝࣌ؒΛ࣮૷ • Ծ૝࣌ؒʹج͖ͮ

    • ΠϕϯτΛൃੜͤ͞Δ • ೚ҙΞΫγϣϯΛ࣮ߦ͢Δ (subscribe, on ͳͲ) • `TestableObservable` `TestableObserver` ͷϑΝΫτϦϝιουΛ࣋ͭ • TestableObservable • ࢦఆͨ͠Ծ૝࣌ؒʹΠϕϯτΛൃੜ͢ΔObservable • ObservableͷϥΠϑαΠΫϧʹൃੜͨ͠subscriptionΛه࿥ • TestableObserver • ड৴ͨ͠ΠϕϯτͱͦͷԾ૝࣌ؒΛηοτʹอ࣋͢ΔObserver
  3. mapΦϖϨʔλͷςετʢ؆қ൛ʣ RxSwift: Observable+StandardSequenceOperatorsTest.swift 
 https://github.com/ReactiveX/RxSwift/blob/master/Tests/RxSwiftTests/Observable+StandardSequenceOperatorsTest.swift#L754-L782 func test_map() { // 1.

    Ծ૝࣌ؒ 0 Λࢦఆ͠TestSchedulerΛੜ੒ let scheduler = TestScheduler(initialClock: 0) // 2. TestableObservable<Int> Λ `Ծ૝࣌ؒ` `஋` Λࢦఆͯ͠ੜ੒ let xs = scheduler.createHotObservable([ next(150, 1), // ୈҰҾ਺: Ծ૝࣌ؒ, ୈೋҾ਺: ஋ next(210, 0), next(240, 4), completed(300) ]) // 3. TestableObserver<Int> Λੜ੒ let observer = scheduler.createObserver(Int.self)
  4. RxSwift ͷ map ͷςετΛ؆ૉԽͨ͠ྫ // 4. Ծ૝࣌ؒ `200` ʹ `observer`

    Λ `xs` ʹ subscribe ͤ͞Δ scheduler.scheduleAt(200) { xs.map { $0 * 2 } .subscribe(observer) .addDisposableTo(self.disposeBag) } // 5. schedulerΛ։࢝ scheduler.start() let expectedEvents = [ next(210, 0 * 2), next(240, 4 * 2), completed(300) ] /// 6-1. TestableObserver ͕ड৴ͨ͠ΠϕϯτΛݕূ XCTAssertEqual(observer.events, expectedEvents) let expectedSubscriptions = [ Subscription(200, 300) ] /// 6-2. TestableObservable ͕ subscribe/unsubscribe ͞ΕͨԾ૝࣌ؒΛݕূ XCTAssertEqual(xs.subscriptions, expectedSubscriptions) }
  5. ViewModel class SearchViewModel { let disposeBag = DisposeBag() // .loading,

    .loaded, .error var state: Variable<State> = Variable(.loaded([])) var users: Variable<[User]> = Variable([]) let client: Client init(client: Client) { self.client = client } func searchFollowers(ofUser user: String) { state.value = .loading client.fetchFollowers(ofUser: user) .subscribe { event in switch event { case .next(let users) : self.state.value = .loaded(users) self.users.value = users case .error(let e): self.state.value = .error(e as? Client.Error ?? .unknown) self.users.value = [] default: // ignore `.completed` break } } .addDisposableTo(disposeBag) } }
  6. ςετ؍఺ͰͷϙΠϯτ 1. Client ΛΠχγϟϥΠβͰड͚औΔ
 
 
 2. searchFollowers() ಺Ͱ Client.fetchFollowers()

    Λίʔϧ͢ Δ init(client: Client) { self.client = client } func searchFollowers(ofUser user: String) { state.value = .loading client.fetchFollowers(ofUser: user) .subscribe { event in … } .addDisposableTo(disposeBag) }
  7. Mock Client class MockClient: Client { // ௨৴݁Ռͱͯ͠࢖͏Observable let response:

    TestableObservable<[User]> init(response: TestableObservable<[User]>) { self.response = response super.init() } override func fetchFollowers(ofUser user: String) -> Observable<[User]> { // `response` Λ໭Γ஋ͱͯ͠return return response.asObservable() } }
  8. ςετ: SearchViewModel.state ʢ௨৴੒ޭ࣌ʣ • stateϓϩύςΟ͸ searchFollowers() ͷݺͼग़͠ʹΑΓมԽ͢Δɻ func test_state_when_searchFollowers_succeeded() {

    let users = [User(id: 12091114, name: "tunepolo")] // 1. TestableObserverΛੜ੒ let observer = scheduler.createObserver(State.self) // 2. ௨৴݁Ռͱͯ͠࢖͏ColdͳObservableΛੜ੒ let xs = scheduler.createColdObservable([ next(100, users) ]) // 3. ObservableΛ࢖ͬͯMockClientΛੜ੒ let client = MockClient(response: xs) // 4. MockClientΛ࢖ͬͯSearchViewModelΛੜ੒ let viewModel = SearchViewModel(client: client)
  9. ςετ: SearchViewModel.state ͷঢ়ଶมԽ // 5. Ծ૝࣌ؒ 100: TestableObservableΛsubscribe scheduler.scheduleAt(100) {

    viewModel.state.asObservable() .subscribe(observer) .addDisposableTo(self.disposeBag) } // 6. Ծ૝࣌ؒ 200: viewModelͷsearchFollowers()Λίʔϧ scheduler.scheduleAt(200) { viewModel.searchFollowers(ofUser: "tasanobu") } // 7. schedulerΛ։࢝ scheduler.start() // 8. ظ଴஋ͱͷൺֱ let expectedEvents = [ next(100, State.loaded([])), next(200, State.loading), next(300, State.loaded(users)) // ☝ 300 = subscribe@200 + 100 ɹɹɹɹɹɹɹ// Cold ObservableͷͨΊ ] XCTAssertEqual(observer.events, expectedEvents)
  10. RxTest: ςετίʔυͷྲྀΕ 1. TestScheduler Λੜ੒ 2. ݕূ͍ͨ͠ΠϕϯτΛTestableObservableͱͯ͠ੜ੒ 3. ॲཧ݁ՌΛอ࣋͢ΔTestableObserverΛੜ੒ 4.

    TestableObserverʹTestableObservableΛsubscribeͤ͞Δ 5. TestSchedulerΛελʔτ 6. TestableObserver.events ΍ 
 TestableObservable.subscriptions Λݕূ Reactiveͳίʔυͷςετ͸ɺͱ͔͔ͬΓʹ͘͘ײ͡Δ͔΋͠Ε·ͤΜ͕ɺ ࣍ͷྲྀΕͰςετΛॻ͚·͢