SlideShare uma empresa Scribd logo
1 de 47
Baixar para ler offline
APIClient
2018/12/14 HAKATA Test Night #1 #hakata_test_night


(@ktanaka117)
• / @ktanaka117
•
• :
• R&D Swift TDD
• PEAKS iOS
Booth iOS 

💪
APIClient
2018/12/14 HAKATA Test Night #1 #hakata_test_night


(@ktanaka117)
•
•
•
•
•
•
•
•
AccessToken/RefreshToken
AccessToken
• AccessToken AuthError
• Refresh→Retry AccessToken …
• 5
•
•
• 1 1APICall API
• Auth Error retry 1
• 5
•
•
•
• Etc…
Android 

OkHttp
•
• iOS
•
iOS


• Interactor - APIClient SessionManager
• Refresh Request
• Refresh Request
• APIKit→Alamofire
• APIKit Refresh/Retry
• Request-Completion 

Alamofire
: RequestRetrier/RequestAdapter
: RequestRetrier/RequestAdapter
• APIClient
• APIClient
•
• 1
• 2
• 2
• HTTP Status
- 1
•
• [200]
• [400]
• [401] refresh 

- 1
•
• [200]
• [400]
• [401]
• [401, 200(refresh), 200(retry)]
• [401, 200(refresh), 400(retry)]
• [401, 200(refresh), 401(retry)]
Refresh/Retry 

- 2
•
• [200(a), 200(b)] (ab )
• [400(a), 400(b)] (ab )
• [401(a), 401(b)]
- 2
•
• [200(a), 200(b)] / [400(a), 400(b)] (ab )
• [401(a), 200(a, refresh), 200(a, retry), 200(b)] (ab )
• [401(a), 200(a, refresh), 400(a, retry), 200(b)] (ab )
• [401(a), 400(a, refresh), 401(b)] (ab )
• [401(a), 401(a, refresh), 401(b)] (ab )
- 2
•
- 2
•
• [200(a), 200(b)] / [400(a), 400(b)] (ab )
• [400(a), 401(b)] / [200(a) / 400(b)] (ab , 1 )
• [401(a), 401(b), 200(a, refresh), 200(a, retry), 200(b, retry)] (b Refresh )
• [401(a), 200(a, refresh), 401(b), 200(a, retry), 200(b, retry)] (b Refresh )
• etc…


• Stub
• XCTContext
• AccessToken, RefreshToken
• AccessToken, RefreshToken
• Stub
• XCTContext
• AccessToken, RefreshToken
• AccessToken, RefreshToken
🙇
Stub
var responses = [authError, successWithAccessToken, success]

stub(condition: isHost("example.com")) { request in
return responses.removeFirst()
}
// ......
// ...
OHHTTPStubs.removeAllStubs()
responses test function …
Stub
HTTPStub.activate(
condition: isHost("example.com"),
responses: [authError, successWithAccessToken, success])
// ......
// ...
HTTPStub.deactivate()
responses 

Stub
struct HTTPStub {
static func activate(condition: @escaping OHHTTPStubsTestBlock,
responses: [OHHTTPStubsResponse]) {
var responsesArray = responses
stub(condition: condition) { request in
let response = responsesArray.removeFirst()
return response
}
}
static func deactivate() {
OHHTTPStubs.removeAllStubs()
}
}
Blog
XCTContext
XCTContext.runActivity(named: case1) { [weak self] _ in
HTTPStub.activate(responses: [authError, successWithAccesstoken, success])
expectation.expectedFulfillmentCount = 1

sessionManager.requestData(TestRequest())
.subscribe(onSuccess: { data, _ in
let success = try? JSONDecoder().decodeSuccess(from: data)
XCTAssertEqual(success, OHHTTPStubsResponse.Success(data: "Success"))
expectation.fulfill()
}, onError: { error in
XCTFail(error.localizedDescription)
expectation.fulfill()
}).disposed(by: disposeBag)
self?.waitForExpectations(timeout: 1.0)
clean()
}
XCTContext
XCTContext.runActivity(named: case1) { [weak self] _ in
HTTPStub.activate(responses: [authError, successWithAccesstoken, success])
expectation.expectedFulfillmentCount = 1

sessionManager.requestData(TestRequest())
.subscribe(onSuccess: { data, _ in
let success = try? JSONDecoder().decodeSuccess(from: data)
XCTAssertEqual(success, OHHTTPStubsResponse.Success(data: "Success"))
expectation.fulfill()
}, onError: { error in
XCTFail(error.localizedDescription)
expectation.fulfill()
}).disposed(by: disposeBag)
self?.waitForExpectations(timeout: 1.0)
clean()
}
👃
XCTContext
XCTContext.runActivity(named: case1) { [weak self] _ in
HTTPStub.activate(responses: [authError, successWithAccesstoken, success])
expectation.expectedFulfillmentCount = 1

sessionManager.requestData(TestRequest())
.subscribe(onSuccess: { data, _ in
let success = try? JSONDecoder().decodeSuccess(from: data)
XCTAssertEqual(success, OHHTTPStubsResponse.Success(data: "Success"))
expectation.fulfill()
}, onError: { error in
XCTFail(error.localizedDescription)
expectation.fulfill()
}).disposed(by: disposeBag)
self?.waitForExpectations(timeout: 1.0)
clean()
}
Stub 👀
XCTContext
XCTContext.runActivity(named: case1) { [weak self] _ in
HTTPStub.activate(responses: [authError, successWithAccesstoken, success])
expectation.expectedFulfillmentCount = 1

sessionManager.requestData(TestRequest())
.subscribe(onSuccess: { data, _ in
let success = try? JSONDecoder().decodeSuccess(from: data)
XCTAssertEqual(success, OHHTTPStubsResponse.Success(data: "Success"))
expectation.fulfill()
}, onError: { error in
XCTFail(error.localizedDescription)
expectation.fulfill()
}).disposed(by: disposeBag)
self?.waitForExpectations(timeout: 1.0)
clean()
}
expectation 👀
XCTContext
XCTContext.runActivity(named: case1) { [weak self] _ in
HTTPStub.activate(responses: [authError, successWithAccesstoken, success])
expectation.expectedFulfillmentCount = 1

sessionManager.requestData(TestRequest())
.subscribe(onSuccess: { data, _ in
let success = try? JSONDecoder().decodeSuccess(from: data)
XCTAssertEqual(success, OHHTTPStubsResponse.Success(data: "Success"))
expectation.fulfill()
}, onError: { error in
XCTFail(error.localizedDescription)
expectation.fulfill()
}).disposed(by: disposeBag)
self?.waitForExpectations(timeout: 1.0)
clean()
} 👀
XCTContext
XCTContext.runActivity(named: case1) { [weak self] _ in
HTTPStub.activate(responses: [authError, successWithAccesstoken, success])
expectation.expectedFulfillmentCount = 1

sessionManager.requestData(TestRequest())
.subscribe(onSuccess: { data, _ in
let success = try? JSONDecoder().decodeSuccess(from: data)
XCTAssertEqual(success, OHHTTPStubsResponse.Success(data: “Success"))
expectation.fulfill()
}, onError: { error in
XCTFail(error.localizedDescription)
expectation.fulfill()
}).disposed(by: disposeBag)
self?.waitForExpectations(timeout: 1.0)
clean()
}
👀
XCTContext
extension XCTContext {
static func runWaitActivity(testCase: XCTestCase,
name name: String,
timeout: TimeInterval = 1.0,
prepare: (() -> Void)? = nil,
then: (XCTestExpectation) -> Void,
clean: (() -> Void)? = nil) {
runActivity(named: named) { _ in
let expectation = name
prepare?()
then(expectation)
testCase.waitForExpectations(timeout: timeout, handler: nil)
clean?()
}
}
}
XCTContext
XCTContext
.runWaitActivity(testCase: self, named: case1, prepare: {
HTTPStub.activate(responses: [authError, successWithAccesstoken, success])
}, then: { expectation in
expectation.expectedFulfillmentCount = 1
sessionManager.requestData(TestRequest())
.subscribe(onSuccess: { data, _ in
let success = try? JSONDecoder().decodeSuccess(from: data)
XCTAssertEqual(success, OHHTTPStubsResponse.Success(data: "Success"))
expectation.fulfill()
}, onError: { error in
XCTFail(error.localizedDescription)
expectation.fulfill()
})
.disposed(by: disposeBag)
}, clean: clean)


😄
•
• 

•

Mais conteúdo relacionado

Mais procurados

JavaOne 2013: Java 8 - The Good Parts
JavaOne 2013: Java 8 - The Good PartsJavaOne 2013: Java 8 - The Good Parts
JavaOne 2013: Java 8 - The Good PartsKonrad Malawski
 
Advanced Durable Functions - Serverless Meetup Tokyo - Feb 2018
Advanced Durable Functions - Serverless Meetup Tokyo - Feb 2018Advanced Durable Functions - Serverless Meetup Tokyo - Feb 2018
Advanced Durable Functions - Serverless Meetup Tokyo - Feb 2018Chris Gillum
 
Azure Durable Functions (2019-03-30)
Azure Durable Functions (2019-03-30) Azure Durable Functions (2019-03-30)
Azure Durable Functions (2019-03-30) Paco de la Cruz
 
Durable functions 2.0 (2019-10-10)
Durable functions 2.0 (2019-10-10)Durable functions 2.0 (2019-10-10)
Durable functions 2.0 (2019-10-10)Paco de la Cruz
 
Serverless APIs, the Good, the Bad and the Ugly (2019-09-19)
Serverless APIs, the Good, the Bad and the Ugly (2019-09-19)Serverless APIs, the Good, the Bad and the Ugly (2019-09-19)
Serverless APIs, the Good, the Bad and the Ugly (2019-09-19)Paco de la Cruz
 
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
Node.js: Continuation-Local-Storage and the Magic of AsyncListenerNode.js: Continuation-Local-Storage and the Magic of AsyncListener
Node.js: Continuation-Local-Storage and the Magic of AsyncListenerIslam Sharabash
 
(1) c sharp introduction_basics_dot_net
(1) c sharp introduction_basics_dot_net(1) c sharp introduction_basics_dot_net
(1) c sharp introduction_basics_dot_netNico Ludwig
 
Azure Durable Functions (2018-06-13)
Azure Durable Functions (2018-06-13)Azure Durable Functions (2018-06-13)
Azure Durable Functions (2018-06-13)Paco de la Cruz
 
Software engineering ⊇ Software testing
Software engineering ⊇ Software testingSoftware engineering ⊇ Software testing
Software engineering ⊇ Software testingPavel Tcholakov
 
Automate that
Automate thatAutomate that
Automate thatAtlassian
 
The Road To Reactive with RxJava JEEConf 2016
The Road To Reactive with RxJava JEEConf 2016The Road To Reactive with RxJava JEEConf 2016
The Road To Reactive with RxJava JEEConf 2016Frank Lyaruu
 
JIRA REST Client for Python - Atlassian Summit 2012
JIRA REST Client for Python - Atlassian Summit 2012JIRA REST Client for Python - Atlassian Summit 2012
JIRA REST Client for Python - Atlassian Summit 2012Atlassian
 
Tech Talks_25.04.15_Session 3_Tibor Sulyan_Distributed coordination with zook...
Tech Talks_25.04.15_Session 3_Tibor Sulyan_Distributed coordination with zook...Tech Talks_25.04.15_Session 3_Tibor Sulyan_Distributed coordination with zook...
Tech Talks_25.04.15_Session 3_Tibor Sulyan_Distributed coordination with zook...EPAM_Systems_Bulgaria
 
Finding the right stuff, an intro to Elasticsearch (at Rug::B)
Finding the right stuff, an intro to Elasticsearch (at Rug::B) Finding the right stuff, an intro to Elasticsearch (at Rug::B)
Finding the right stuff, an intro to Elasticsearch (at Rug::B) Michael Reinsch
 
Reactive Thinking in Java
Reactive Thinking in JavaReactive Thinking in Java
Reactive Thinking in JavaYakov Fain
 
SolrJ: Power and Pitfalls - Jason Gerlowski, Lucidworks
SolrJ: Power and Pitfalls - Jason Gerlowski, LucidworksSolrJ: Power and Pitfalls - Jason Gerlowski, Lucidworks
SolrJ: Power and Pitfalls - Jason Gerlowski, LucidworksLucidworks
 
Automating OWASP ZAP - DevCSecCon talk
Automating OWASP ZAP - DevCSecCon talk Automating OWASP ZAP - DevCSecCon talk
Automating OWASP ZAP - DevCSecCon talk Simon Bennetts
 
FullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + AngularFullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + AngularLoiane Groner
 
Nestjs MasterClass Slides
Nestjs MasterClass SlidesNestjs MasterClass Slides
Nestjs MasterClass SlidesNir Kaufman
 

Mais procurados (20)

JavaOne 2013: Java 8 - The Good Parts
JavaOne 2013: Java 8 - The Good PartsJavaOne 2013: Java 8 - The Good Parts
JavaOne 2013: Java 8 - The Good Parts
 
Advanced Durable Functions - Serverless Meetup Tokyo - Feb 2018
Advanced Durable Functions - Serverless Meetup Tokyo - Feb 2018Advanced Durable Functions - Serverless Meetup Tokyo - Feb 2018
Advanced Durable Functions - Serverless Meetup Tokyo - Feb 2018
 
Azure Durable Functions (2019-03-30)
Azure Durable Functions (2019-03-30) Azure Durable Functions (2019-03-30)
Azure Durable Functions (2019-03-30)
 
Durable functions 2.0 (2019-10-10)
Durable functions 2.0 (2019-10-10)Durable functions 2.0 (2019-10-10)
Durable functions 2.0 (2019-10-10)
 
Serverless APIs, the Good, the Bad and the Ugly (2019-09-19)
Serverless APIs, the Good, the Bad and the Ugly (2019-09-19)Serverless APIs, the Good, the Bad and the Ugly (2019-09-19)
Serverless APIs, the Good, the Bad and the Ugly (2019-09-19)
 
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
Node.js: Continuation-Local-Storage and the Magic of AsyncListenerNode.js: Continuation-Local-Storage and the Magic of AsyncListener
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
 
(1) c sharp introduction_basics_dot_net
(1) c sharp introduction_basics_dot_net(1) c sharp introduction_basics_dot_net
(1) c sharp introduction_basics_dot_net
 
Azure Durable Functions (2018-06-13)
Azure Durable Functions (2018-06-13)Azure Durable Functions (2018-06-13)
Azure Durable Functions (2018-06-13)
 
Software engineering ⊇ Software testing
Software engineering ⊇ Software testingSoftware engineering ⊇ Software testing
Software engineering ⊇ Software testing
 
Automate that
Automate thatAutomate that
Automate that
 
The Road To Reactive with RxJava JEEConf 2016
The Road To Reactive with RxJava JEEConf 2016The Road To Reactive with RxJava JEEConf 2016
The Road To Reactive with RxJava JEEConf 2016
 
JIRA REST Client for Python - Atlassian Summit 2012
JIRA REST Client for Python - Atlassian Summit 2012JIRA REST Client for Python - Atlassian Summit 2012
JIRA REST Client for Python - Atlassian Summit 2012
 
#ajn3.lt.marblejenka
#ajn3.lt.marblejenka#ajn3.lt.marblejenka
#ajn3.lt.marblejenka
 
Tech Talks_25.04.15_Session 3_Tibor Sulyan_Distributed coordination with zook...
Tech Talks_25.04.15_Session 3_Tibor Sulyan_Distributed coordination with zook...Tech Talks_25.04.15_Session 3_Tibor Sulyan_Distributed coordination with zook...
Tech Talks_25.04.15_Session 3_Tibor Sulyan_Distributed coordination with zook...
 
Finding the right stuff, an intro to Elasticsearch (at Rug::B)
Finding the right stuff, an intro to Elasticsearch (at Rug::B) Finding the right stuff, an intro to Elasticsearch (at Rug::B)
Finding the right stuff, an intro to Elasticsearch (at Rug::B)
 
Reactive Thinking in Java
Reactive Thinking in JavaReactive Thinking in Java
Reactive Thinking in Java
 
SolrJ: Power and Pitfalls - Jason Gerlowski, Lucidworks
SolrJ: Power and Pitfalls - Jason Gerlowski, LucidworksSolrJ: Power and Pitfalls - Jason Gerlowski, Lucidworks
SolrJ: Power and Pitfalls - Jason Gerlowski, Lucidworks
 
Automating OWASP ZAP - DevCSecCon talk
Automating OWASP ZAP - DevCSecCon talk Automating OWASP ZAP - DevCSecCon talk
Automating OWASP ZAP - DevCSecCon talk
 
FullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + AngularFullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + Angular
 
Nestjs MasterClass Slides
Nestjs MasterClass SlidesNestjs MasterClass Slides
Nestjs MasterClass Slides
 

Semelhante a トークンリフレッシュ処理を含むAPIClientのテスト #hakata_test_night

Phoenix + Reactで 社内システムを 密かに作ってる
Phoenix + Reactで 社内システムを 密かに作ってるPhoenix + Reactで 社内システムを 密かに作ってる
Phoenix + Reactで 社内システムを 密かに作ってるTakahiro Kobaru
 
ERRest - Designing a good REST service
ERRest - Designing a good REST serviceERRest - Designing a good REST service
ERRest - Designing a good REST serviceWO Community
 
[NDC 2019] Enterprise-Grade Serverless
[NDC 2019] Enterprise-Grade Serverless[NDC 2019] Enterprise-Grade Serverless
[NDC 2019] Enterprise-Grade ServerlessKatyShimizu
 
[NDC 2019] Functions 2.0: Enterprise-Grade Serverless
[NDC 2019] Functions 2.0: Enterprise-Grade Serverless[NDC 2019] Functions 2.0: Enterprise-Grade Serverless
[NDC 2019] Functions 2.0: Enterprise-Grade ServerlessKatyShimizu
 
HashiCorp Vault Plugin Infrastructure
HashiCorp Vault Plugin InfrastructureHashiCorp Vault Plugin Infrastructure
HashiCorp Vault Plugin InfrastructureNicolas Corrarello
 
Nordic APIs - Automatic Testing of (RESTful) API Documentation
Nordic APIs - Automatic Testing of (RESTful) API DocumentationNordic APIs - Automatic Testing of (RESTful) API Documentation
Nordic APIs - Automatic Testing of (RESTful) API DocumentationRouven Weßling
 
Velocity EU 2014 — Offline-first web apps
Velocity EU 2014 — Offline-first web appsVelocity EU 2014 — Offline-first web apps
Velocity EU 2014 — Offline-first web appsandrewsmatt
 
Anton Moldovan "Load testing which you always wanted"
Anton Moldovan "Load testing which you always wanted"Anton Moldovan "Load testing which you always wanted"
Anton Moldovan "Load testing which you always wanted"Fwdays
 
IVS CTO Night And Day 2018 Winter - [re:Cap] Serverless & Mobile
IVS CTO Night And Day 2018 Winter - [re:Cap] Serverless & MobileIVS CTO Night And Day 2018 Winter - [re:Cap] Serverless & Mobile
IVS CTO Night And Day 2018 Winter - [re:Cap] Serverless & MobileAmazon Web Services Japan
 
Salesforce Batch processing - Atlanta SFUG
Salesforce Batch processing - Atlanta SFUGSalesforce Batch processing - Atlanta SFUG
Salesforce Batch processing - Atlanta SFUGvraopolisetti
 
Codestrong 2012 breakout session hacking titanium
Codestrong 2012 breakout session   hacking titaniumCodestrong 2012 breakout session   hacking titanium
Codestrong 2012 breakout session hacking titaniumAxway Appcelerator
 
Tale of ISUCON and Its Bench Tools
Tale of ISUCON and Its Bench ToolsTale of ISUCON and Its Bench Tools
Tale of ISUCON and Its Bench ToolsSATOSHI TAGOMORI
 
Make your gui shine with ajax solr
Make your gui shine with ajax solrMake your gui shine with ajax solr
Make your gui shine with ajax solrlucenerevolution
 
Introduction to Node.js
Introduction to Node.jsIntroduction to Node.js
Introduction to Node.jsRichard Lee
 
Java-Jersey 到 Python-Flask 服務不中斷重構之旅
Java-Jersey 到 Python-Flask 服務不中斷重構之旅Java-Jersey 到 Python-Flask 服務不中斷重構之旅
Java-Jersey 到 Python-Flask 服務不中斷重構之旅Max Lai
 
ITT 2014 - Erik Hellmann - Android Programming - Smarter and Better Networking
ITT 2014 - Erik Hellmann - Android Programming - Smarter and Better NetworkingITT 2014 - Erik Hellmann - Android Programming - Smarter and Better Networking
ITT 2014 - Erik Hellmann - Android Programming - Smarter and Better NetworkingIstanbul Tech Talks
 
MLflow at Company Scale
MLflow at Company ScaleMLflow at Company Scale
MLflow at Company ScaleDatabricks
 

Semelhante a トークンリフレッシュ処理を含むAPIClientのテスト #hakata_test_night (20)

Phoenix + Reactで 社内システムを 密かに作ってる
Phoenix + Reactで 社内システムを 密かに作ってるPhoenix + Reactで 社内システムを 密かに作ってる
Phoenix + Reactで 社内システムを 密かに作ってる
 
ERRest - Designing a good REST service
ERRest - Designing a good REST serviceERRest - Designing a good REST service
ERRest - Designing a good REST service
 
[NDC 2019] Enterprise-Grade Serverless
[NDC 2019] Enterprise-Grade Serverless[NDC 2019] Enterprise-Grade Serverless
[NDC 2019] Enterprise-Grade Serverless
 
[NDC 2019] Functions 2.0: Enterprise-Grade Serverless
[NDC 2019] Functions 2.0: Enterprise-Grade Serverless[NDC 2019] Functions 2.0: Enterprise-Grade Serverless
[NDC 2019] Functions 2.0: Enterprise-Grade Serverless
 
HashiCorp Vault Plugin Infrastructure
HashiCorp Vault Plugin InfrastructureHashiCorp Vault Plugin Infrastructure
HashiCorp Vault Plugin Infrastructure
 
Nordic APIs - Automatic Testing of (RESTful) API Documentation
Nordic APIs - Automatic Testing of (RESTful) API DocumentationNordic APIs - Automatic Testing of (RESTful) API Documentation
Nordic APIs - Automatic Testing of (RESTful) API Documentation
 
Velocity EU 2014 — Offline-first web apps
Velocity EU 2014 — Offline-first web appsVelocity EU 2014 — Offline-first web apps
Velocity EU 2014 — Offline-first web apps
 
Anton Moldovan "Load testing which you always wanted"
Anton Moldovan "Load testing which you always wanted"Anton Moldovan "Load testing which you always wanted"
Anton Moldovan "Load testing which you always wanted"
 
Socket.io
Socket.ioSocket.io
Socket.io
 
IVS CTO Night And Day 2018 Winter - [re:Cap] Serverless & Mobile
IVS CTO Night And Day 2018 Winter - [re:Cap] Serverless & MobileIVS CTO Night And Day 2018 Winter - [re:Cap] Serverless & Mobile
IVS CTO Night And Day 2018 Winter - [re:Cap] Serverless & Mobile
 
Salesforce Batch processing - Atlanta SFUG
Salesforce Batch processing - Atlanta SFUGSalesforce Batch processing - Atlanta SFUG
Salesforce Batch processing - Atlanta SFUG
 
Codestrong 2012 breakout session hacking titanium
Codestrong 2012 breakout session   hacking titaniumCodestrong 2012 breakout session   hacking titanium
Codestrong 2012 breakout session hacking titanium
 
NodeJS
NodeJSNodeJS
NodeJS
 
Curator intro
Curator introCurator intro
Curator intro
 
Tale of ISUCON and Its Bench Tools
Tale of ISUCON and Its Bench ToolsTale of ISUCON and Its Bench Tools
Tale of ISUCON and Its Bench Tools
 
Make your gui shine with ajax solr
Make your gui shine with ajax solrMake your gui shine with ajax solr
Make your gui shine with ajax solr
 
Introduction to Node.js
Introduction to Node.jsIntroduction to Node.js
Introduction to Node.js
 
Java-Jersey 到 Python-Flask 服務不中斷重構之旅
Java-Jersey 到 Python-Flask 服務不中斷重構之旅Java-Jersey 到 Python-Flask 服務不中斷重構之旅
Java-Jersey 到 Python-Flask 服務不中斷重構之旅
 
ITT 2014 - Erik Hellmann - Android Programming - Smarter and Better Networking
ITT 2014 - Erik Hellmann - Android Programming - Smarter and Better NetworkingITT 2014 - Erik Hellmann - Android Programming - Smarter and Better Networking
ITT 2014 - Erik Hellmann - Android Programming - Smarter and Better Networking
 
MLflow at Company Scale
MLflow at Company ScaleMLflow at Company Scale
MLflow at Company Scale
 

Mais de Kenji Tanaka

FatViewControllerを安全に書き換える方法が見つからなかったので、どういう痛みを許容するか考えた #iosdc
FatViewControllerを安全に書き換える方法が見つからなかったので、どういう痛みを許容するか考えた #iosdcFatViewControllerを安全に書き換える方法が見つからなかったので、どういう痛みを許容するか考えた #iosdc
FatViewControllerを安全に書き換える方法が見つからなかったので、どういう痛みを許容するか考えた #iosdcKenji Tanaka
 
リリース前のリグレッションテストがめんどい!のでMagic PodでUIテストを試してみる #pixiv_app_night
リリース前のリグレッションテストがめんどい!のでMagic PodでUIテストを試してみる #pixiv_app_nightリリース前のリグレッションテストがめんどい!のでMagic PodでUIテストを試してみる #pixiv_app_night
リリース前のリグレッションテストがめんどい!のでMagic PodでUIテストを試してみる #pixiv_app_nightKenji Tanaka
 
ポストモーテムやってみた #yjbonfire
ポストモーテムやってみた #yjbonfireポストモーテムやってみた #yjbonfire
ポストモーテムやってみた #yjbonfireKenji Tanaka
 
2つの同期 4つの状態 #pixiv_ios_arch
2つの同期 4つの状態 #pixiv_ios_arch2つの同期 4つの状態 #pixiv_ios_arch
2つの同期 4つの状態 #pixiv_ios_archKenji Tanaka
 
2つの同期 4つの状態 #app_mp
2つの同期 4つの状態 #app_mp2つの同期 4つの状態 #app_mp
2つの同期 4つの状態 #app_mpKenji Tanaka
 
2つの同期 4つの状態 #roppongiswift
2つの同期 4つの状態 #roppongiswift2つの同期 4つの状態 #roppongiswift
2つの同期 4つの状態 #roppongiswiftKenji Tanaka
 
よく使うテストヘルパーの紹介 #ios_test_night
よく使うテストヘルパーの紹介 #ios_test_nightよく使うテストヘルパーの紹介 #ios_test_night
よく使うテストヘルパーの紹介 #ios_test_nightKenji Tanaka
 
Swiftで聞いておぼえるテスト書き
Swiftで聞いておぼえるテスト書きSwiftで聞いておぼえるテスト書き
Swiftで聞いておぼえるテスト書きKenji Tanaka
 
設計時空のリファクタリング
設計時空のリファクタリング設計時空のリファクタリング
設計時空のリファクタリングKenji Tanaka
 
WACATE 2018 Summer
WACATE 2018 SummerWACATE 2018 Summer
WACATE 2018 SummerKenji Tanaka
 
テスト駆動開発入門 by Swift
テスト駆動開発入門 by Swiftテスト駆動開発入門 by Swift
テスト駆動開発入門 by SwiftKenji Tanaka
 
An iOS Engineer challenges Web.
An iOS Engineer challenges Web.An iOS Engineer challenges Web.
An iOS Engineer challenges Web.Kenji Tanaka
 
エンジニアのためのブログ講座Ver4
エンジニアのためのブログ講座Ver4エンジニアのためのブログ講座Ver4
エンジニアのためのブログ講座Ver4Kenji Tanaka
 
TDDやってみよ
TDDやってみよTDDやってみよ
TDDやってみよKenji Tanaka
 
ストレス社会に生きる、iOSエンジニアにオススメする百合の世界と作品
ストレス社会に生きる、iOSエンジニアにオススメする百合の世界と作品ストレス社会に生きる、iOSエンジニアにオススメする百合の世界と作品
ストレス社会に生きる、iOSエンジニアにオススメする百合の世界と作品Kenji Tanaka
 
節子、それViewControllerやない...、FatViewControllerや...。
節子、それViewControllerやない...、FatViewControllerや...。節子、それViewControllerやない...、FatViewControllerや...。
節子、それViewControllerやない...、FatViewControllerや...。Kenji Tanaka
 
iOS 11からのDeviceCheck #とは
iOS 11からのDeviceCheck #とはiOS 11からのDeviceCheck #とは
iOS 11からのDeviceCheck #とはKenji Tanaka
 
設計に答えはないから探してみよう
設計に答えはないから探してみよう設計に答えはないから探してみよう
設計に答えはないから探してみようKenji Tanaka
 
iOS 11からのアプリ間ファイル共有
iOS 11からのアプリ間ファイル共有iOS 11からのアプリ間ファイル共有
iOS 11からのアプリ間ファイル共有Kenji Tanaka
 
iOS 11からのアプリ間ファイル共有_公開用
iOS 11からのアプリ間ファイル共有_公開用iOS 11からのアプリ間ファイル共有_公開用
iOS 11からのアプリ間ファイル共有_公開用Kenji Tanaka
 

Mais de Kenji Tanaka (20)

FatViewControllerを安全に書き換える方法が見つからなかったので、どういう痛みを許容するか考えた #iosdc
FatViewControllerを安全に書き換える方法が見つからなかったので、どういう痛みを許容するか考えた #iosdcFatViewControllerを安全に書き換える方法が見つからなかったので、どういう痛みを許容するか考えた #iosdc
FatViewControllerを安全に書き換える方法が見つからなかったので、どういう痛みを許容するか考えた #iosdc
 
リリース前のリグレッションテストがめんどい!のでMagic PodでUIテストを試してみる #pixiv_app_night
リリース前のリグレッションテストがめんどい!のでMagic PodでUIテストを試してみる #pixiv_app_nightリリース前のリグレッションテストがめんどい!のでMagic PodでUIテストを試してみる #pixiv_app_night
リリース前のリグレッションテストがめんどい!のでMagic PodでUIテストを試してみる #pixiv_app_night
 
ポストモーテムやってみた #yjbonfire
ポストモーテムやってみた #yjbonfireポストモーテムやってみた #yjbonfire
ポストモーテムやってみた #yjbonfire
 
2つの同期 4つの状態 #pixiv_ios_arch
2つの同期 4つの状態 #pixiv_ios_arch2つの同期 4つの状態 #pixiv_ios_arch
2つの同期 4つの状態 #pixiv_ios_arch
 
2つの同期 4つの状態 #app_mp
2つの同期 4つの状態 #app_mp2つの同期 4つの状態 #app_mp
2つの同期 4つの状態 #app_mp
 
2つの同期 4つの状態 #roppongiswift
2つの同期 4つの状態 #roppongiswift2つの同期 4つの状態 #roppongiswift
2つの同期 4つの状態 #roppongiswift
 
よく使うテストヘルパーの紹介 #ios_test_night
よく使うテストヘルパーの紹介 #ios_test_nightよく使うテストヘルパーの紹介 #ios_test_night
よく使うテストヘルパーの紹介 #ios_test_night
 
Swiftで聞いておぼえるテスト書き
Swiftで聞いておぼえるテスト書きSwiftで聞いておぼえるテスト書き
Swiftで聞いておぼえるテスト書き
 
設計時空のリファクタリング
設計時空のリファクタリング設計時空のリファクタリング
設計時空のリファクタリング
 
WACATE 2018 Summer
WACATE 2018 SummerWACATE 2018 Summer
WACATE 2018 Summer
 
テスト駆動開発入門 by Swift
テスト駆動開発入門 by Swiftテスト駆動開発入門 by Swift
テスト駆動開発入門 by Swift
 
An iOS Engineer challenges Web.
An iOS Engineer challenges Web.An iOS Engineer challenges Web.
An iOS Engineer challenges Web.
 
エンジニアのためのブログ講座Ver4
エンジニアのためのブログ講座Ver4エンジニアのためのブログ講座Ver4
エンジニアのためのブログ講座Ver4
 
TDDやってみよ
TDDやってみよTDDやってみよ
TDDやってみよ
 
ストレス社会に生きる、iOSエンジニアにオススメする百合の世界と作品
ストレス社会に生きる、iOSエンジニアにオススメする百合の世界と作品ストレス社会に生きる、iOSエンジニアにオススメする百合の世界と作品
ストレス社会に生きる、iOSエンジニアにオススメする百合の世界と作品
 
節子、それViewControllerやない...、FatViewControllerや...。
節子、それViewControllerやない...、FatViewControllerや...。節子、それViewControllerやない...、FatViewControllerや...。
節子、それViewControllerやない...、FatViewControllerや...。
 
iOS 11からのDeviceCheck #とは
iOS 11からのDeviceCheck #とはiOS 11からのDeviceCheck #とは
iOS 11からのDeviceCheck #とは
 
設計に答えはないから探してみよう
設計に答えはないから探してみよう設計に答えはないから探してみよう
設計に答えはないから探してみよう
 
iOS 11からのアプリ間ファイル共有
iOS 11からのアプリ間ファイル共有iOS 11からのアプリ間ファイル共有
iOS 11からのアプリ間ファイル共有
 
iOS 11からのアプリ間ファイル共有_公開用
iOS 11からのアプリ間ファイル共有_公開用iOS 11からのアプリ間ファイル共有_公開用
iOS 11からのアプリ間ファイル共有_公開用
 

Último

Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 

Último (20)

Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 

トークンリフレッシュ処理を含むAPIClientのテスト #hakata_test_night

  • 1. APIClient 2018/12/14 HAKATA Test Night #1 #hakata_test_night 
 (@ktanaka117)
  • 2. • / @ktanaka117 • • : • R&D Swift TDD • PEAKS iOS
  • 3.
  • 5. APIClient 2018/12/14 HAKATA Test Night #1 #hakata_test_night 
 (@ktanaka117)
  • 7.
  • 9. • AccessToken AuthError • Refresh→Retry AccessToken … • 5 • • • 1 1APICall API
  • 10. • Auth Error retry 1 • 5
  • 12.
  • 13.
  • 16. • Interactor - APIClient SessionManager • Refresh Request • Refresh Request • APIKit→Alamofire • APIKit Refresh/Retry • Request-Completion 
 Alamofire
  • 19.
  • 21. • 1 • 2 • 2 • HTTP Status
  • 22. - 1 • • [200] • [400] • [401] refresh 

  • 23. - 1 • • [200] • [400] • [401] • [401, 200(refresh), 200(retry)] • [401, 200(refresh), 400(retry)] • [401, 200(refresh), 401(retry)] Refresh/Retry 

  • 24. - 2 • • [200(a), 200(b)] (ab ) • [400(a), 400(b)] (ab ) • [401(a), 401(b)]
  • 25. - 2 • • [200(a), 200(b)] / [400(a), 400(b)] (ab ) • [401(a), 200(a, refresh), 200(a, retry), 200(b)] (ab ) • [401(a), 200(a, refresh), 400(a, retry), 200(b)] (ab ) • [401(a), 400(a, refresh), 401(b)] (ab ) • [401(a), 401(a, refresh), 401(b)] (ab )
  • 27. - 2 • • [200(a), 200(b)] / [400(a), 400(b)] (ab ) • [400(a), 401(b)] / [200(a) / 400(b)] (ab , 1 ) • [401(a), 401(b), 200(a, refresh), 200(a, retry), 200(b, retry)] (b Refresh ) • [401(a), 200(a, refresh), 401(b), 200(a, retry), 200(b, retry)] (b Refresh ) • etc…
  • 28.
  • 29.
  • 30.
  • 31.
  • 32. • Stub • XCTContext • AccessToken, RefreshToken • AccessToken, RefreshToken
  • 33. • Stub • XCTContext • AccessToken, RefreshToken • AccessToken, RefreshToken 🙇
  • 34. Stub var responses = [authError, successWithAccessToken, success]
 stub(condition: isHost("example.com")) { request in return responses.removeFirst() } // ...... // ... OHHTTPStubs.removeAllStubs() responses test function …
  • 35. Stub HTTPStub.activate( condition: isHost("example.com"), responses: [authError, successWithAccessToken, success]) // ...... // ... HTTPStub.deactivate() responses 

  • 36. Stub struct HTTPStub { static func activate(condition: @escaping OHHTTPStubsTestBlock, responses: [OHHTTPStubsResponse]) { var responsesArray = responses stub(condition: condition) { request in let response = responsesArray.removeFirst() return response } } static func deactivate() { OHHTTPStubs.removeAllStubs() } }
  • 37. Blog
  • 38. XCTContext XCTContext.runActivity(named: case1) { [weak self] _ in HTTPStub.activate(responses: [authError, successWithAccesstoken, success]) expectation.expectedFulfillmentCount = 1
 sessionManager.requestData(TestRequest()) .subscribe(onSuccess: { data, _ in let success = try? JSONDecoder().decodeSuccess(from: data) XCTAssertEqual(success, OHHTTPStubsResponse.Success(data: "Success")) expectation.fulfill() }, onError: { error in XCTFail(error.localizedDescription) expectation.fulfill() }).disposed(by: disposeBag) self?.waitForExpectations(timeout: 1.0) clean() }
  • 39. XCTContext XCTContext.runActivity(named: case1) { [weak self] _ in HTTPStub.activate(responses: [authError, successWithAccesstoken, success]) expectation.expectedFulfillmentCount = 1
 sessionManager.requestData(TestRequest()) .subscribe(onSuccess: { data, _ in let success = try? JSONDecoder().decodeSuccess(from: data) XCTAssertEqual(success, OHHTTPStubsResponse.Success(data: "Success")) expectation.fulfill() }, onError: { error in XCTFail(error.localizedDescription) expectation.fulfill() }).disposed(by: disposeBag) self?.waitForExpectations(timeout: 1.0) clean() } 👃
  • 40. XCTContext XCTContext.runActivity(named: case1) { [weak self] _ in HTTPStub.activate(responses: [authError, successWithAccesstoken, success]) expectation.expectedFulfillmentCount = 1
 sessionManager.requestData(TestRequest()) .subscribe(onSuccess: { data, _ in let success = try? JSONDecoder().decodeSuccess(from: data) XCTAssertEqual(success, OHHTTPStubsResponse.Success(data: "Success")) expectation.fulfill() }, onError: { error in XCTFail(error.localizedDescription) expectation.fulfill() }).disposed(by: disposeBag) self?.waitForExpectations(timeout: 1.0) clean() } Stub 👀
  • 41. XCTContext XCTContext.runActivity(named: case1) { [weak self] _ in HTTPStub.activate(responses: [authError, successWithAccesstoken, success]) expectation.expectedFulfillmentCount = 1
 sessionManager.requestData(TestRequest()) .subscribe(onSuccess: { data, _ in let success = try? JSONDecoder().decodeSuccess(from: data) XCTAssertEqual(success, OHHTTPStubsResponse.Success(data: "Success")) expectation.fulfill() }, onError: { error in XCTFail(error.localizedDescription) expectation.fulfill() }).disposed(by: disposeBag) self?.waitForExpectations(timeout: 1.0) clean() } expectation 👀
  • 42. XCTContext XCTContext.runActivity(named: case1) { [weak self] _ in HTTPStub.activate(responses: [authError, successWithAccesstoken, success]) expectation.expectedFulfillmentCount = 1
 sessionManager.requestData(TestRequest()) .subscribe(onSuccess: { data, _ in let success = try? JSONDecoder().decodeSuccess(from: data) XCTAssertEqual(success, OHHTTPStubsResponse.Success(data: "Success")) expectation.fulfill() }, onError: { error in XCTFail(error.localizedDescription) expectation.fulfill() }).disposed(by: disposeBag) self?.waitForExpectations(timeout: 1.0) clean() } 👀
  • 43. XCTContext XCTContext.runActivity(named: case1) { [weak self] _ in HTTPStub.activate(responses: [authError, successWithAccesstoken, success]) expectation.expectedFulfillmentCount = 1
 sessionManager.requestData(TestRequest()) .subscribe(onSuccess: { data, _ in let success = try? JSONDecoder().decodeSuccess(from: data) XCTAssertEqual(success, OHHTTPStubsResponse.Success(data: “Success")) expectation.fulfill() }, onError: { error in XCTFail(error.localizedDescription) expectation.fulfill() }).disposed(by: disposeBag) self?.waitForExpectations(timeout: 1.0) clean() } 👀
  • 44. XCTContext extension XCTContext { static func runWaitActivity(testCase: XCTestCase, name name: String, timeout: TimeInterval = 1.0, prepare: (() -> Void)? = nil, then: (XCTestExpectation) -> Void, clean: (() -> Void)? = nil) { runActivity(named: named) { _ in let expectation = name prepare?() then(expectation) testCase.waitForExpectations(timeout: timeout, handler: nil) clean?() } } }
  • 45. XCTContext XCTContext .runWaitActivity(testCase: self, named: case1, prepare: { HTTPStub.activate(responses: [authError, successWithAccesstoken, success]) }, then: { expectation in expectation.expectedFulfillmentCount = 1 sessionManager.requestData(TestRequest()) .subscribe(onSuccess: { data, _ in let success = try? JSONDecoder().decodeSuccess(from: data) XCTAssertEqual(success, OHHTTPStubsResponse.Success(data: "Success")) expectation.fulfill() }, onError: { error in XCTFail(error.localizedDescription) expectation.fulfill() }) .disposed(by: disposeBag) }, clean: clean) 
 😄
  • 46.