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
WACATE2019_summer_BPP
Search
Daiki Katayama
June 15, 2019
Programming
1
2.3k
WACATE2019_summer_BPP
WACATE2019 夏のBPPセッションスライドです。
Daiki Katayama
June 15, 2019
Tweet
Share
More Decks by Daiki Katayama
See All by Daiki Katayama
iOSアプリのパフォーマンス計測をおさらいする
kariad
2
9.4k
アプリのパフォーマンスを継続的に計測する
kariad
7
16k
Xcodeのカバレッジ計測ではなぜブランチカバレッジが取れないのだろうか?
kariad
3
4.8k
Viewのテストどうしてますか?
kariad
2
1.6k
コードカバレッジとの付き合い方を知ってテストを書く
kariad
2
2.5k
開発者として学ぶソフトウェアテスト
kariad
2
1k
Other Decks in Programming
See All in Programming
퇴근 후 1억이 거래되는 서비스 만들기 | 내가 AI를 사용하는 방법
maryang
2
510
NIKKEI Tech Talk#38
cipepser
0
430
AI POSにおけるLLM Observability基盤の導入 ― サイバーエージェントDXインターン成果報告
hekuchan
0
400
Amazon Bedrock Knowledge Bases Hands-on
konny0311
0
130
AsyncSequenceとAsyncStreamのプロポーザルを全部読む!!
s_shimotori
1
250
AIを駆使して新しい技術を効率的に理解する方法
nogu66
0
290
Bakuraku E2E Scenario Test System Architecture #bakuraku_qa_study
teyamagu
PRO
0
490
Blazing Fast UI Development with Compose Hot Reload (Bangladesh KUG, October 2025)
zsmb
2
490
なんでRustの環境構築してないのにRust製のツールが動くの? / Why Do Rust-Based Tools Run Without a Rust Environment?
ssssota
14
48k
Tangible Code
chobishiba
3
500
iOSでSVG画像を扱う
kishikawakatsumi
0
190
2026年向け会社紹介資料
misu
0
110
Featured
See All Featured
Designing for Performance
lara
610
69k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
22k
Become a Pro
speakerdeck
PRO
29
5.6k
Designing Experiences People Love
moore
142
24k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
54k
Making the Leap to Tech Lead
cromwellryan
135
9.6k
Why You Should Never Use an ORM
jnunemaker
PRO
60
9.6k
Building Applications with DynamoDB
mza
96
6.7k
Making Projects Easy
brettharned
120
6.4k
Building a Modern Day E-commerce SEO Strategy
aleyda
45
8k
Testing 201, or: Great Expectations
jmmastey
46
7.8k
Build The Right Thing And Hit Your Dates
maggiecrowley
38
2.9k
Transcript
։ൃऀ͔ΒݟΔςετ 2019/06/15~16 WACATE2019 Ն BPPηογϣϯ kariad/͔Γ͋Ͳ(@kariad_uu) 1
ࣗݾհ • kariad / @kariad_uu • ยࢁ େथ • ΦΠγοΫεɾϥɾେ
iOS App Developer • / / V / ςετ / ઃܭ / ྉཧ / ήʔϜ 2
ςετͱͷؔΘΓ • ৽ଔ: SIer ͻͨ͢ΒؤுΔखಈςετɺऴΘΒͳ͍ɺؼΕͳ͍ɺਏ͍…. • ҟಈ: ΞδϟΠϧɺTDDɺςετָ͍͠ • స৬:
ΞδϟΠϧɺUnitςετಋೖɺςετ͍͖ͬͯ • QAΤϯδχΞɺςετΤϯδχΞͱݺΕΔํͱҰॹʹࣄΛͨ͜͠ ͱͳ͍Ͱ͢ 3
ࠓ͢͜ͱ • લճͷࢲͷϙδγϣϯϖʔύʔৼΓฦΓ • ։ൃऀ(ࢲ)͜͏͍͏෩ʹςετʹ͖߹ͬͯ·͢ͱ͍͏ - ςετͷϞνϕʔγϣϯ - ։ൃऀ͕ςετΛ͠ͳ͍(Ͱ͖ͳ͍)ཧ༝ 4
ҙʂ • ͋͘·Ͱࢲͷओ؍Ͱ͢ɻશͯͷ։ൃऀ͕͜͏Ͱ͋Δʂͱ͍ ͏Ͱͳ͍ͷͰྃ͝ঝ͍ͩ͘͞
લճ(WACATE2018 ౙ)ͷ ࢲͷϙδγϣϯϖʔύʔ 6
7
վΊͯݟͨ࣌ͷࢲͷײ • ΈΜͳͱൺͯϑΥϯτ͕Ͱ͔͍ • †ͱ͔ͬͯதೋප • ͳΜ͔ΤϞ͍͚ͩ • ਖ਼ͪΐͬͱஏ͔͔ͣͬͨ͠… 8
ͭ·ΓԿ͕ݴ͍͔ͨͬͨͷ͔ • ։ൃऀ͔ΒࢹͰͷςετͷ͍ ςετ͕͋Δ͜ͱͰ৺ཧత҆શੑͷ͋Δ։ൃ͕Ͱ͖Δ ͰΔ͔ΒʹޮతʹΓ͍ͨ • ςετ͕͖͔ͩΒྑͯ͘͠Ͷ ςετք۾ͷίϛϡχςΟॳࢀՃͩͬͨ 9
• ࠓճΓ߹͍ͱ͔΄΅͍ͳ͍ͷͰؾܰʹ͔͚ͯ͘͠ ΕΔͱخ͍͠Ͱ͢ 10
։ൃऀͷςετͷ͖߹͍ํ
ςετͷϞνϕʔγϣϯ (ࢲͳΓʹ) 12
• ࢲͨͪͷϛογϣϯϢʔβʔʹͱͬͯՁ͋Δ αʔϏεΛఏڙ͢Δ͜ͱ • Ձ͕͋Δ = ͓٬༷(Ϣʔβʔ)͕خ͍͔͠ 13
• Ͱ࠷ॳ͔Β࠷େԽ͞ΕͨՁΛఏڙ͢Δͷ͍͠ • ߟ͑ͨ͜ͱ͕ਖ਼͍͠(Ձ͕͋Δ)ͱݶΒͳ͍ ϦʔϯɾελʔτΞοϓ 14
ϦʔϯɾελʔτΞοϓ 15
ϦʔϯɾελʔτΞοϓ • ݁ہͲΜͳʹ͍͍ͷΛߟ͑ͨͱ͜ΖͰͦΕࢥ͍ࠐΈԾ આʹ͗͢ͳ͍ • MVP(Minimum Valuable Product)Ͱݕূ͢Δ • Ծઆ
→ Ծઆݕূ → ֶͼ →ҙࢥܾఆͷαΠΫϧΛճ͢ 16
࠷ۙͷτϨϯυʁ (σʔλੳΛݩʹͨ͠։ൃ) • ԾઆΛݩʹ࣮ͯ͠ϦϦʔε • σʔλΛऔಘͯ͠ੳ • ੳ݁ՌΛݩʹվળͯ͠ϦϦʔε
• ͲͪΒͱʹ͔͘ૣ͘αΠΫϧΛճ͍ͨ͠ • ͱ͍͑όά͕͋Γਖ਼ৗʹ͑ͳ͚ΕԾઆݕূͰ͖ͳ ͍ ࠷ݶCheckingߦ͍͍ͨ 18
• ΞδϟΠϧ։ൃऀͱͯ͠ૣ͘Ձͷ͋ΔαʔϏεΛఏ ڙ͢ΔͨΊʹCheckingΛ͍ͨ͠ ʢ࣭͕͔ͦͦͬͨΒՁԼ͕Δ…ʣ 19
͡Ό͋ͳΜͰChecking(ࠓճUnitςετ) Βͳ͍ͷʁ 20
• ΊΜͲ͍͘͞ • ςετʹڵຯ͕ͳ͍ • Γํ͕Θ͔Βͳ͍ • CheckingͷॏཁੑΛཧղ͍ͯ͠ͳ͍
• ΊΜͲ͍͘͞ • ςετʹڵຯ͕ͳ͍ • Γํ͕Θ͔Βͳ͍ • CheckingͷॏཁੑΛཧղ͍ͯ͠ͳ͍ ͬͱݴ͏ͱɺ Γͨͯ͘Ͱ͖ͳ͍
• ΊΜͲ͍͘͞ • ςετʹڵຯ͕ͳ͍ • Γํ͕Θ͔Βͳ͍ • CheckingͷॏཁੑΛཧղ͍ͯ͠ͳ͍ ͬͱݴ͏ͱɺ Γͨͯ͘Ͱ͖ͳ͍
ࢲ͕ߟ͑ΔUnitςετΛ Βͳ͍ཧ༝ͷେ͖ͳҰͭ
Unitςετ࣮ͬͯͦΜͳʹ ؆୯Ͱͳ͍ 24
ςετΛॻ͘ͷ͕͍͠ཧ༝ • ςετ͕ॻ͖͍͢ઃܭ(Testable)ʹͳ͍ͬͯͳ͍ͱॻ͘͜ ͱ͕͍͠ • (ແཧཧ)ॻ͚ͯځ۶Ͱมߋʹऑ͘ͳΔ • ޙ͔Βઃܭมߋຊʹେม…(ςετ͕ͳ͍ͱঘߋ) 25
• ଟ͘ͷ߹ઃܭʹ͕͋Δ • ͪΖΜϑϩʔతͳͷ߹͋Δ UnitςετΛॻ͘ϑϩʔʹͳ͍ͬͯͳ͍ɻ͕࣌ؒͳ͍ɻ 26
ͦͦઃܭͱ ”ؔ৺ͷʹΑͬͯ ෳࡶͳΛ୯७ͳͷ܈ͱͯ͠Γ͚Δ͜ͱ” -iOSΞϓϦઃܭύλʔϯೖ P23 ΑΓ 27
• ࠷ۙυϝΠϯతʹٕज़తʹෳࡶԽ͍ͯ͠Δ • ͦͷͨΊʹઃܭΛߦ͍ෳࡶ͞ʹཱ͔ͪ͏ • ͖ͪΜͱઃܭ͞Ε͍ͯΔ = ͕୯७Խ͞Ε͍ͯΔ TestableͷୈҰา
28
ઃܭύλʔϯ(ΞʔΩςΫνϟ) • MVC / MVP / MVVM / Clean Architecture
/ Flux… • ઃܭํͱͯ͠ͷϕετϓϥΫςΟεू • ͜ΕΒͷଟ͘Testableಉ࣌ʹߟ͑ΒΕ͍ͯΔ 29
ςετ͕ॻ͖͍͢ઃܭͱ • ͕୯७Խ͞Ε͍ͯΔ Ϟδϡʔϧ͝ͱʹςετ͍͕ͨ͠γϯϓϧͰ໌֬ • Ϟδϡʔϧؒͷґଘੑ͕ͳ͍ ςετ͍͕ͨ͠ଞϞδϡʔϧͷӨڹΛड͚ͳ͍ 30
ෳࡶͳΛ࣋ͬͨϞδϡʔϧ • xxઍߦΈ͍ͨͳΫϥε • ͗ͯ͢ԿΛ͍ͬͯΔͷ͔Θ͔Βͳ͍ϝιου • ͨΒͱίϝϯτͰઆ໌ͯ͋͠Δ(ݸਓతҙݟ) 31
աଟΛͲ͏ݟ͚Δ͔ʁ 32
“ίʔυͷΛௌ͘” 33
• ςετ͕ॻ͖ͮΒ͍… • ॲཧ͕ෳࡶԽ͖͍ͯͯ͠Δ… • ඞͣͦ͜ʹࠟ͋Δ • ίʔυͷष͍ͱ 34
ઃܭͷݪଇ • ༗໊ͳͷͰSOLIDݪଇ • ୯Ұݪଇɺ։์ดݪଇɺϦείϑͷஔݪଇɺΠϯ λʔϑΣʔεͷݪଇɺґଘؔٯసͷݪଇ • ઃܭͷݪଇΛ༻͍ͯίʔυͷष͍ΛऔΓআ͘
Ϟδϡʔϧؒͷґଘੑ͕͋Δ • ଞϞδϡʔϧͷ࣮͕มΘΔ͜ͱͰͪ͜Βͷॲཧ͕ӨڹΛड ͚ͯ͠·͏͜ͱ 36
func didTapSearchButton(text: String?) { ~~~ লུ ~~~ SearchModel().search(searchWord: searchWord) {
result in switch result { case .success(let events): ~~ লུ ~~ case .failure: ~~ লུ ~~ } } } 37
func didTapSearchButton(text: String?) { ~~~ লུ ~~~ SearchModel().search(searchWord: searchWord) {
result in switch result { case .success(let events): ~~ লུ ~~ case .failure: ~~ লུ ~~ } } } ͜͜ͷॲཧΛςετ͍ͨ͠ 38
func didTapSearchButton(text: String?) { ~~~ লུ ~~~ SearchModel().search(searchWord: searchWord) {
result in switch result { case .success(let events): ~~ লུ ~~ case .failure: ~~ লུ ~~ } } } SearchModelͷ࣮ʹ ґଘ͍ͯ͠Δ 39
func didTapSearchButton(text: String?) { ~~~ লུ ~~~ SearchModel().search(searchWord: searchWord) {
result in switch result { case .success(let events): ~~ লུ ~~ case .failure: ~~ লུ ~~ } } } SearchModelͷ࣮͕มΘΔͱ ͪ͜Βͷ݁ՌมΘͬͯ͠·͏ 40
func didTapSearchButton(text: String?, model: SearchModel) { ~~~ লུ ~~~ model.search(searchWord:
searchWord) { result in switch result { case .success(let events): ~~ লུ ~~ case .failure: ~~ লུ ~~ } } } ֎ଆ͔ΒΦϒδΣΫτΛ ͢Α͏ʹ 41
func didTapSearchButton(text: String?, model: SearchModelProtocol) { ~~~ লུ ~~~ model.search(searchWord:
searchWord) { result in switch result { case .success(let events): ~~ লུ ~~ case .failure: ~~ লུ ~~ } } } ͢ܕΛநԽ͞Εͨ ܕʹ͢Δ 42
43 protocol SearchEventModelProtocol { func search(searchWord: String, completion: @escaping ((Result<[ConnpassEvent]>)
-> ())) } Protocol
class FakeSearchEventModel: SearchEventModelProtocol { var search_successValue = [ConnpassEvent]() func search(searchWord:
String, completion: @escaping ((Result<[ConnpassEvent]>) -> ())) { search_callCount += 1 search_arguments = searchWord completion(.success(search_successValue)) } } class FakeFailureSearchEventModel: SearchEventModelProtocol { func search(searchWord: String, completion: @escaping ((Result<[ConnpassEvent]>) -> ())) { search_arguments = searchWord completion(.failure) } } ελϒ ґଘ͢ΔΦϒδΣΫτͷ݁ՌΛ ίϯτϩʔϧͰ͖Δ
• ͜ͷґଘ͢ΔΦϒδΣΫτΛ֎ଆ͔Β্ͯ͛͠Δ͜ͱ ΛDI(Dependency Injection)ͱ͍͏ • ͢ΦϒδΣΫτநԽ͞Ε͍ͯΔͷͰɺςετίʔ υ͔ΒελϒΛ͢͜ͱ͕Ͱ͖Δ • Modelͷ࣮ʹґଘͤͣޭɺࣦഊͦΕͧΕͷςετ͕ ՄೳͱͳΔ
45
• ࣮ࡍʹJavaͰ͋ΕMockitoΛ͑͏গָ͠ʹͳͬ ͨΓ͋Δ • ͕ɺSwiftͰϥΠϒϥϦΛ༻͍ͳ͍͜ͷύλʔϯ͕ൺֱ తଟ͍ • ͜ΕΒͷ͕ࣝͳ͍ͱॻ͘͜ͱ͕͍͠ 46
ઃܭҎ֎ͷཁૉ • ςεςΟϯάϑϨʔϜϫʔΫͷ͍ํ(XCTest, Quick/Nimble) • ඇಉظॲཧͷςετ • ಛʹඇಉظ׳Εͳ͍ͱ͍͠ iOSͰReactiveX(RxSwift)͕ελϯμʔυ(Combine) 47
ReactiveX • FRP(Functional Reactive Programming) • ͬ͘͟Γ͍͏ͱStreamͱ͍͏࣌ؒͷྲྀΕΛ༻͍ͯඇಉظॲཧΛ؆ ܿʹॻ͚ΔΑ͏ʹͨ͠ख๏ • บ͕͋ΔͷͰ׳Εͳ͍ͱগ͍͠͠
• ςετͰಉظతʹѻͬͯ͋͛ͨΓɺςετ༻ͷStreamͰཧͨ͠Γ 48
ςετΛॻͨ͘ΊʹΒͳ͖Ό ͍͚ͳ͍͜ͱଟ͍ 49
• Βͳ͍ͷͰͳ͘ΔεΩϧ͕ແ͔ͬͨ • Γͨͯ͘αΫοͱͰ͖ΔઃܭͰແ͔ͬͨ • Ͱ͜ͷลͷࣝɺͲ͜Ͱֶ͍͍ͷ…ʁ
ֶͿͨΊͷ໌Δ͍ஹ͠ 51
ίϛϡχςΟͷಇ͖ • ςετʹؔ͢Δษڧձ (TestNight) • ΫϥυϑΝϯσΟϯά(PEAKS)ʹΑΔ Android / iOSςετશॻץߦ(iOS8݄༧ఆ) 52
ٕज़ॻయ લճࢲ͜Μͳͷग़͠·ͨ͠
·ͱΊ • গͳ͘ͱϞόΠϧΞϓϦ։ൃऀͰςετʹର͢Δҙࣝ ؒҧ͍ͳ͘ߴ·͍ͬͯΔ(ͱࢥ͏) • αʔόɺϑϩϯτͳͲϑϨʔϜϫʔΫͷൃలΞδϟΠϧ ͷਁಁͱͱʹҙࣝߴ·͍ͬͯΔΑ͏ʹݟ͑Δ 54
• ؍ଌൣғͰςετΛͲ͏ʹ͔͍ͨ͠ͱࢥ͍ͬͯΔ։ൃ ऀ͕ଟ͍ • Ձ͋ΔαʔϏεΛಧ͚͍ͨͱ͍͏ࢥ͍୭͠ಉ͡ͳ ͣ • ։ൃऀ/ςετΤϯδχΞ͕ڠྗͯ͠ςετʹର͢Δݟ ΛਂΊ͍͚ͯͨΒخ͍͠ 55
• iOSΞϓϦઃܭύλʔϯೖ ؔ ོٛɾদؗ େًɾླ େوɾਿ্ ༸ฏɾ࢙ ᠳ৽ɾాத ݡ ࣏ɾՃ౻
ਓ ஶ https://peaks.cc/books/iOS_architecture • Clean Architecture ୡਓʹֶͿιϑτΣΞͷߏͱઃܭ Robert.C.Martinஶ ֯ యɾߴ ਖ਼߂ ༁ ࢀߟॻ੶
• Test Night https://testnight.connpass.com/ • Androidςετશॻ https://peaks.cc/books/android_testing • iOSςετશॻ https://peaks.cc/iOS_testing
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ 58