Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Test techniques for iOS app using Web API
Search
cockscomb
April 24, 2014
Programming
4
38k
Test techniques for iOS app using Web API
My presentation at Consumer Service Engineer MeetUp Vol.1 ~iOS編~ (
http://eventdots.jp/event/47442
)
cockscomb
April 24, 2014
Tweet
Share
More Decks by cockscomb
See All by cockscomb
jq at the Shortcuts
cockscomb
1
1.9k
GraphQL放談
cockscomb
4
2k
GraphQL Highway
cockscomb
28
8.5k
吉田を支える技術
cockscomb
0
2.3k
コーポレートサイトを静的化してAmplify Consoleにデプロイする
cockscomb
0
3.4k
ユーザインターフェイスと非同期処理
cockscomb
5
1.9k
GUIアプリケーションの構造と設計
cockscomb
10
10k
イカリング2におけるシングルページアプリケーション
cockscomb
2
7.5k
あなたの知らない UIKit の世界 — UITableView に UITextView を置きたい
cockscomb
1
7.5k
Other Decks in Programming
See All in Programming
Streamlitで実現できるようになったこと、実現してくれたこと
ayumu_yamaguchi
2
230
SwiftでMCPサーバーを作ろう!
giginet
PRO
2
210
Android 16KBページサイズ対応をはじめからていねいに
mine2424
0
740
プロダクトという一杯を作る - プロダクトチームが味の責任を持つまでの煮込み奮闘記
hiliteeternal
0
290
副作用と戦う PHP リファクタリング ─ ドメインイベントでビジネスロジックを解きほぐす
kajitack
3
480
MySQL9でベクトルカラム登場!PHP×AWSでのAI/類似検索はこう変わる
suguruooki
1
250
CLI ツールを Go ライブラリ として再実装する理由 / Why reimplement a CLI tool as a Go library
ktr_0731
3
660
なぜあなたのオブザーバビリティ導入は頓挫するのか
ryota_hnk
3
510
NEWT Backend Evolution
xpromx
1
160
リバースエンジニアリング新時代へ! GhidraとClaude DesktopをMCPで繋ぐ/findy202507
tkmru
4
1.3k
オンコール⼊⾨〜ページャーが鳴る前に、あなたが備えられること〜 / Before The Pager Rings
yktakaha4
2
1.2k
PHPUnitの限界をPlaywrightで補完するテストアプローチ
yuzneri
0
350
Featured
See All Featured
The Cult of Friendly URLs
andyhume
79
6.5k
A Modern Web Designer's Workflow
chriscoyier
695
190k
Product Roadmaps are Hard
iamctodd
PRO
54
11k
Making Projects Easy
brettharned
117
6.3k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
15
1.6k
The Cost Of JavaScript in 2023
addyosmani
51
8.6k
[RailsConf 2023] Rails as a piece of cake
palkan
55
5.7k
Code Reviewing Like a Champion
maltzj
524
40k
How to train your dragon (web standard)
notwaldorf
96
6.1k
GraphQLとの向き合い方2022年版
quramy
49
14k
Intergalactic Javascript Robots from Outer Space
tanoku
271
27k
Transcript
Web APIΛར༻͢Δ iOSΞϓϦͷςετٕ๏
None
cockscomb
id:cockscomb ΞϓϦέʔγϣϯΤϯδχΞ iOSΞϓϦɾWebΞϓϦέʔγϣϯ Perl, JavaScript, Objective-C ͯͳϒϩάνʔϜ WWDC 2014
ͯͳϒϩά Presso B!KUMA Ψʔϧζ
ͯͳαϚʔΠϯλʔϯ Web APIΛར༻͢ΔiOSΞϓϦ࡞
–id:murakaming “iOS ଆͬ͟ͱݟ͚ͨͲɺ͜͏͍͏ حྷͳίʔυ͕খ͍͞αϯϓϧͰͳ͘ Ұࣜἧ͍ͬͯΔͷຊʹوॏͩ͠ ༗Γ͗͢Δɻ”
–id:griffin-stewie “ͦΕͳΓʹ࣮ઓܦݧ͕͋ΔਓͰ ͬͯͳͦ͞͏ͩͬͨΓΒͳͦ͏ͳ͜ͱΛ αϥοͱݟͤͯ͘Ε͍ͯΔ”
Web APIΛར༻͢Δ iOSΞϓϦͷςετٕ๏
Web API JSON REST·ͨAppઐ༻ APIόʔδϣϯ
API is living
ੜ͖͍ͯΔAPIͷͨΊͷ ςετ
ԿΛςετ͢Δͷ͔ ظͲ͓ΓͷHTTP request͕ൃߦ͞ΕΔ URL (ϗετύεɺΫΤϦ) HTTP method, header, body ༷ʑͳHTTP
responseʹର͢Δ;Δ·͍ Τϥʔ͕ى͖ͨͱ͖
ಓ۩ • OHHTTPStubs • NTLHTTPStubServer
OHHTTPStubs • HTTPͷ௨৴Λstub͢Δ • NSURLProtocolΛར༻͍ͯ͠Δ
__block APIClient *client; __block NSURLRequest *lastRequest; __block OHHTTPStubsResponse *preferredResponse; !
beforeAll(^{ client = [APIClient sharedClient]; ! [OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) { if ( [request.HTTPMethod isEqual:@"GET"] && [request.URL.host isEqual:@"example.com"] && [request.URL.path isEqual:@"/api/entries.json"] ) { lastRequest = request; return YES; } return NO; } withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) { return preferredResponse; }]; }); ! afterEach(^{ lastRequest = nil; preferredResponse = nil; }); ! afterAll(^{ [OHHTTPStubs removeAllStubs]; });
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) { if ( [request.HTTPMethod isEqual:@"GET"] && [request.URL.host
isEqual:@"example.com"] && [request.URL.path isEqual:@"/api/entries.json"] ) { lastRequest = request; return YES; } return NO; } withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) { return preferredResponse; }];
NSString *userAgent = lastRequest.allHTTPHeaderFields[@"User-Agent"]; expect([userAgent hasPrefix:@"BKUMAGirls"]).to.beTruthy(); ! ! NSURL *URL
= lastRequest.URL; NSDictionary *query = [CMDQueryStringSerialization dictionaryWithQueryString:URL.query]; ! expect(query[@"entry_id"]).to.equal(@"1234567890");
preferredResponse = [OHHTTPStubsResponse responseWithFileAtPath: OHPathForFileInBundle(@"entries.json", nil) statusCode:200 headers:@{ @"Content-Type" :
@"application/json", }]; ! ! preferredResponse = [OHHTTPStubsResponse responseWithJSONObject:@{ @"test" : @"ok", } statusCode:200 headers:@{ @"Content-Type" : @"application/json", }]; ! ! preferredResponse = [OHHTTPStubsResponse responseWithError: [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorNetworkConnectionLost userInfo:nil]];
OHHTTPStubs • HTTP requestͷ༷ࢠΛݟΔ͜ͱ͕Ͱ͖Δ • ҙͷHTTP responseΛฦ͢͜ͱ͕Ͱ͖Δ • ΤϥʔΛൃੜͤ͞ΒΕΔ •
HTTP bodyऔಘͰ͖ͳ͍
NLTHTTPStubServer • ΞϓϦͷ෦ͰαʔόʔΛಈ͔͢ • CocoaHTTPServerΛར༻ • http://localhost:12345/
#if defined(UNIT_TEST) static NSString *const kAPIRootURLString = @"http://localhost:12345/"; #else static
NSString *const kAPIRootURLString = @"http://example.com/"; #endif
__block NLTHTTPStubServer *server; __block APIClient *client; ! beforeAll(^{ server =
[[NLTHTTPStubServer alloc] init]; [server startServer]; client = [APIClient sharedClient]; }); ! afterAll(^{ [server stopServer]; }); ! afterEach(^{ [server clear]; });
[[[[server expect] forPath:@"/api/bookmarks.json" HTTPMethod:@"POST"] andCheckPostBody:^(NSData *postBody) { ! NSString *body
= [[NSString alloc] initWithData:postBody encoding:NSUTF8StringEncoding]; ! NSDictionary *parameters = [CMDQueryStringSerialization dictionaryWithQueryString:body]; ! expect(parameters[@"entry_id"]).to.equal(@"1234567890"); ! }] andPlainResponse:[@"1" dataUsingEncoding:NSUTF8StringEncoding]]; ! ... ! [server verify];
NLTHTTPStubServer • ࣮ࡍͷαʔόʔͱͯ͠ৼΔ͏ • ҙͷHTTP responseΛฦ͢͜ͱ͕Ͱ͖Δ • HTTP bodyͷ༷ࢠΛݟΔ͜ͱ͕Ͱ͖Δ •
Τϥʔൃੜͤ͞ΒΕͳ͍ • HTTP requestҰ෦औಘͰ͖ͳ͍
ಓ۩ • OHHTTPStubs • NTLHTTPStubServer
ςετͷϝϦοτ • ࣗ༝ͳHTTP response͕࡞ΕΔ • ࣮ࡍʹαʔόʔʹrequest͠ͳͯ͘Α͍ • αʔόʔαΠυͷ࣮Λͭඞཁ͕ͳ͍ • αʔόʔαΠυͷมߋΛࣄલʹࢼͤΔ
• ͍͖ͳΓյΕΔͷΛ͛Δ
ςετ is ศར
None
PR
[PR] ৽αʔϏεΓ·͢ https://mackerel.io/ ϕʔλϢʔβʔ ࣄલडத!!
ੵۃ࠾༻த http://hatenacorp.jp/recruit/