Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
RxTest入門
Search
tasanobu
November 17, 2016
Technology
1.5k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
RxTest入門
第3回RxSwift勉強会で発表した資料です。
https://connpass.com/event/41478/
tasanobu
November 17, 2016
More Decks by tasanobu
See All by tasanobu
Introduction to UIStackView
tasanobu
0
260
Other Decks in Technology
See All in Technology
仕様駆動開発の、その先へ。決める力と確かめる仕組み
inariku
1
140
Technical Project Manager の役割とやりがい、少しだけ AI
yoshiiryo1
0
280
AIテスト自動化と評価駆動開発EDD
happysamurai294
0
110
re:Inventで、人生は変わったのか? / growth-builders-hub-1-reinvent-2026
mhrtech
2
160
AIコーディングエージェント開発_全体像
happysamurai294
0
130
"計画的無茶振り"を通してAIネイティブ世代の新人を育てる
subroh0508
1
130
あなたのDartコードは丸見えかもしれない ~reFlutterで暴くFlutterアプリの中身と多層防御~
zozotech
PRO
0
700
Agent 活用環境の構築・運用のための AWS サービスのご紹介/agentcore-for-building-and-operating-agents
ren8k
1
280
これだけは抑えておきたい!後悔しない re:Invent の過ごし方 / AWS re:Invent 2026 prestudy
kinunori
2
590
[FECONF-2026] 신대륙을 향한 카카오페이증권 프론트엔드 항해기 (이주승)
l1ghthouse
0
320
SLOを阻む不安
sraku2159
0
140
Draft AIエージェントの トークン消費を最小化する 8つの原則
kinopeee
6
1.9k
Featured
See All Featured
Balancing Empowerment & Direction
lara
6
1.3k
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
1k
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.8k
Prompt Engineering for Job Search
mfonobong
0
560
Ethics towards AI in product and experience design
skipperchong
2
450
Everyday Curiosity
cassininazir
0
380
Intergalactic Javascript Robots from Outer Space
tanoku
273
28k
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
460
The Art of Programming - Codeland 2020
erikaheidi
57
14k
Reality Check: Gamification 10 Years Later
codingconduct
0
2.4k
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
74
43k
Transcript
RxTest ೖ 2016/11/17 RxSwiftษڧձ #3
Kazunobu Tasaka About Me @tasanobu
ຊͷ༰ • RxTest ͷ֓ཁ • RxTestΛ༻ͨ͠ςετίʔυͷॻ͖ํ • ·ͱΊ
RxTest ͷ֓ཁ
RxTest ͱ • RxSwift ϨϙδτϦͰఏڙ͞Ε͍ͯΔςετϑϨʔϜ ϫʔΫ • RxSwift ࣗମͷςετʹར༻͞Ε͍ͯΔ •
Cocoapods ͔ΒΠϯετʔϧՄೳ target 'RxTest-SampleTests' do pod 'RxTest', '~> 3.0' pod 'RxSwift', '~> 3.0' pod 'RxCocoa', '~> 3.0' end
RxTest ͷओཁͳΫϥε • TestScheduler • RxTestͷத৺తͳΫϥε • ࣮࣌ؒͱΓ͞ΕͨԾ࣌ؒΛ࣮ • Ծ࣌ؒʹج͖ͮ
• ΠϕϯτΛൃੜͤ͞Δ • ҙΞΫγϣϯΛ࣮ߦ͢Δ (subscribe, on ͳͲ) • `TestableObservable` `TestableObserver` ͷϑΝΫτϦϝιουΛ࣋ͭ • TestableObservable • ࢦఆͨ͠Ծ࣌ؒʹΠϕϯτΛൃੜ͢ΔObservable • ObservableͷϥΠϑαΠΫϧʹൃੜͨ͠subscriptionΛه • TestableObserver • ड৴ͨ͠ΠϕϯτͱͦͷԾ࣌ؒΛηοτʹอ࣋͢ΔObserver
࣮ྫΛݟ͍͖ͯ·͠ΐ͏
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)
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) }
ʙ࣮ફฤʙ GithubͷϑΥϩϫʔݕࡧը໘ ViewModel
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) } }
ςετ؍ͰͷϙΠϯτ 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) }
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() } }
ςετ: 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)
ςετ: 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)
·ͱΊ
RxTest: ςετίʔυͷྲྀΕ 1. TestScheduler Λੜ 2. ݕূ͍ͨ͠ΠϕϯτΛTestableObservableͱͯ͠ੜ 3. ॲཧ݁ՌΛอ࣋͢ΔTestableObserverΛੜ 4.
TestableObserverʹTestableObservableΛsubscribeͤ͞Δ 5. TestSchedulerΛελʔτ 6. TestableObserver.events TestableObservable.subscriptions Λݕূ Reactiveͳίʔυͷςετɺͱ͔͔ͬΓʹ͘͘ײ͡Δ͔͠Ε·ͤΜ͕ɺ ࣍ͷྲྀΕͰςετΛॻ͚·͢
͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠