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
良いテストコードのために悪いテストコードを理解する - 不安定なテスト編: iOSアプリ開発...
Search
yimajo
June 24, 2024
Programming
6.8k
22
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
良いテストコードのために悪いテストコードを理解する - 不安定なテスト編: iOSアプリ開発ユニットテストの場合
「モバイルアプリ開発における良いテストコードの考え方」の発表資料です。
https://trident-qa.connpass.com/event/320151/
yimajo
June 24, 2024
More Decks by yimajo
See All by yimajo
片田舎のおっさん、 Swift Buildのダイアモンド問題解決の不具合修正PRを出すが、解決方法がキャッシュをしないようにすることであり、ビルド時間が伸びると言われてマージされないので高速化もする/swiftbuild
yimajo
0
360
OSSとなったswift-buildで Xcodeのビルドを差し替えられるため 自分でXcodeを直せる時代になっている ダイアモンド問題編
yimajo
3
920
いま中途半端なSwift 6対応をするより、Default ActorやApproachable Concurrencyを有効にしてからでいいんじゃない?
yimajo
2
740
11年かかって やっとVibe Codingに 時代が追いつきましたね
yimajo
1
410
iOSアプリ開発で 関数型プログラミングを実現する The Composable Architectureの紹介
yimajo
3
350
TCAの Shared Stateって どういう仕組みになってんの?
yimajo
0
2.8k
Swift 5.9 からの Observation はiOS17 未満 からも使えて struct の変更検知もできるんすかね?
yimajo
2
1.2k
不安定なテストは200種類あんねん
yimajo
3
1.3k
TCA v0.19.0からのSwitchStore/CaseLetが良い
yimajo
0
2.1k
Other Decks in Programming
See All in Programming
巨大モノリシックアプリ モダン化大作戦
ktcryomm
0
900
Kiroで創り、AgentCoreで繋ぐ!AWSで実践する「AI-DLC」から「AIエージェント統合」までの最新地図
licux
4
660
App Storeの外へ──日本のiOSサイドローディング入門 for iOSDC Japan 2026
yuukiw00w
0
180
20260828_品質と開発生産性を両立させる、AI時代のE2Eテストの考え方
magicpod
0
200
AIとGame Jamで、ゲームを完成させた話
takahirosaeki
0
120
Family mrubyの進捗
kishima
1
110
App Intentsのビルドプロセスを支える技術
kntkymt
0
270
更なる可用性を求めて、5年間運用したKotlinのアプリケーションをGoでリプレイスする話
ken_tunc
0
100
Swift愛好会と私(ウホーイ) / Swift Fan Club and Uhooi
uhooi
0
150
Deep dive into the select statement (GopherCon UK)
jespino
0
180
Heart of Swift Concurrency
koher
0
270
【高い買い物LT会】初任給で話題の国産フィジカルAIを買った話
akagami
PRO
0
150
Featured
See All Featured
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
35
2.8k
What’s in a name? Adding method to the madness
productmarketing
PRO
24
4.2k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2.2k
Agile that works and the tools we love
rasmusluckow
331
22k
Navigating the Design Leadership Dip - Product Design Week Design Leaders+ Conference 2024
apolaine
2
430
The Illustrated Children's Guide to Kubernetes
chrisshort
51
53k
The Cult of Friendly URLs
andyhume
79
7k
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
250
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
440
Balancing Empowerment & Direction
lara
6
1.3k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.6k
GraphQLとの向き合い方2022年版
quramy
50
15k
Transcript
ྑ͍ςετίʔυͷͨΊʹ ѱ͍ςετίʔυΛཧղ͢Δ 2024.6.24 גࣜձࣾΩϡϦΦγςΟιϑτΣΞ @yimajo #ྑ͍ςετίʔυ ෆ҆ఆͳςετฤJ04ΞϓϦ։ൃϢχοτςετͷ߹ 🐲 🤖 ϤϩγΫ
͓ئ͍͠·͢
͔ΜͨΜͳ ࣗݾհ
• ৬ྺ • ৽ଔ: ಋମϝʔΧʔͰLSIΛςετ͢ΔΤϯδχΞ • WebϞόΠϧΞϓϦ։ൃͷιϑτΣΞΤϯδχΞ • Now!: ϓϩαφʔ݉ιϑτΣΞΤϯδχΞ
ຊͷલʹ ࠓճ͢Ϣχοτςετʹ͍ͭͯͷఆٛ ྑ͍ςετͱԿ͔ʹ͍ͭͯ ͳͥςετΛॻ͘ͷ͔
Ҿ༻: Google Testing Blog / Test Size https://testing.googleblog.com/2010/12/test-sizes.html ಛ Small
Medium Large ωοτϫʔΫΞΫηε ͍͍͑ ϩʔΧϧϗετͷΈ ͍ σʔλϕʔε ͍͍͑ ͍ ͍ ϑΝΠϧγεςϜͷΞΫηε ͍͍͑ ͍ ͍ ֎෦γεςϜΛ༻͢Δ ͍͍͑ ਪ͞Εͳ͍ ͍ ෳͷεϨου ͍͍͑ ͍ ͍ Sleep໋ྩ ͍͍͑ ͍ ͍ γεςϜϓϩύςΟ ͍͍͑ ͍ ͍ ੍ݶ࣌ؒ(ඵ) 60 300 900 ఆٛ: Small, Medium, Large Testͷఆٛ 🐲
Ҿ༻: Google Testing Blog / Test Size https://testing.googleblog.com/2010/12/test-sizes.html ಛ Small
Medium Large ωοτϫʔΫΞΫηε ͍͍͑ ϩʔΧϧϗετͷΈ ͍ σʔλϕʔε ͍͍͑ ͍ ͍ ϑΝΠϧγεςϜͷΞΫηε ͍͍͑ ͍ ͍ ֎෦γεςϜΛ༻͢Δ ͍͍͑ ਪ͞Εͳ͍ ͍ ෳͷεϨου ͍͍͑ ͍ ͍ Sleep໋ྩ ͍͍͑ ͍ ͍ γεςϜϓϩύςΟ ͍͍͑ ͍ ͍ ੍ݶ࣌ؒ(ඵ) 60 300 900 ఆٛ: Small, Medium, Large Testͷఆٛ 🐲
Ҿ༻: Google Testing Blog / Test Size https://testing.googleblog.com/2010/12/test-sizes.html ಛ Small
Medium Large ωοτϫʔΫΞΫηε ͍͍͑ ϩʔΧϧϗετͷΈ ͍ σʔλϕʔε ͍͍͑ ͍ ͍ ϑΝΠϧγεςϜͷΞΫηε ͍͍͑ ͍ ͍ ֎෦γεςϜΛ༻͢Δ ͍͍͑ ਪ͞Εͳ͍ ͍ ෳͷεϨου ͍͍͑ ͍ ͍ Sleep໋ྩ ͍͍͑ ͍ ͍ γεςϜϓϩύςΟ ͍͍͑ ͍ ͍ ੍ݶ࣌ؒ(ඵ) 60 300 900 ఆٛ: Small, Medium, Large Testͷఆٛ ʮ͜ͷࢿྉͷ Small/Meidum ʹ͍ͭͯͷςετͷͰ͢ʯ 🐲
ఆٛ: ྑ͍ςετͱʁ ιϑτΣΞͷ࣭Λ ʢ্͛Δͱ͍͏͔ʣམͱ͞ͳ͍ͨΊʹ ։ൃऀͷʹཱͭࣗಈԽ 🐲
ఆٛ: ྑ͍ςετͱʁ ιϑτΣΞͷ࣭Λ ʢ্͛Δͱ͍͏͔ʣམͱ͞ͳ͍ͨΊʹ ։ൃऀͷʹཱͭࣗಈԽ ʮͪΖΜؒతʹΞϓϦΛͬͯ͘ΕΔϢʔβʔͷʹཱͭͱ͍͏͜ͱͰ͢ʯ 🐲
ςετͷ۩ମతͳϝϦοτ Ҿ༻: ॻ੶ʮGoogle ͷιϑτΣΞΤϯδχΞϦϯάʯ • σόοά࣌ؒͷݮগ • มߋͷ৴པͷ૿େ • υΩϡϝϯςʔγϣϯͷվળ
• ϨϏϡʔͷ୯७Խ • ࢥྀʹΉઃܭ • ߴͰߴ࣭ͳϦϦʔε
ςετͷ۩ମతͳϝϦοτ Ҿ༻: ॻ੶ʮ୯ମςετͷߟ͑ํ/͍ํʯ • ςετΛॻ͘ͱઃܭ͕ྑ͘ͳΔ • ʢϓϩμΫτΛʣ࣋ଓՄೳͳͷʹ͢Δ
ςετͷ۩ମతͳϝϦοτ • ςετΛॻ͘ͱઃܭ͕ྑ͘ͳΔ • ʢϓϩμΫτΛʣ࣋ଓՄೳͳͷʹ͢Δ • σόοά࣌ؒͷݮগ • มߋͷ৴པͷ૿େ •
υΩϡϝϯςʔγϣϯͷվળ • ϨϏϡʔͷ୯७Խ • ࢥྀʹΉઃܭ • ߴͰߴ࣭ͳϦϦʔε 🤖
ςετͷ۩ମతͳϝϦοτ • ςετΛॻ͘ͱઃܭ͕ྑ͘ͳΔ • ʢϓϩμΫτΛʣ࣋ଓՄೳͳͷʹ͢Δ • σόοά࣌ؒͷݮগ • มߋͷ৴པͷ૿େ •
υΩϡϝϯςʔγϣϯͷվળ • ϨϏϡʔͷ୯७Խ • ࢥྀʹΉઃܭ • ߴͰߴ࣭ͳϦϦʔε ʮςετΛॻ࣮࣌ؒ͘ߦ࣌ؒͷσϝϦοτແࢹͳͷʁʯ 🤖
ςετ͋Γͳ͠ͷଛӹذ͕͋Δ ࢀߟ: ॻ੶ʮ୯ମςετͷߟ͑ํ/͍ํʯ ʮ࠷ॳςετΛॻ͕͔͔͍࣌ؒͬͯͯ͘ɺ ɹɹ࣍ୈʹͦΕ͕ଛͰͳ͘ʹඞਢʹʯ 🐲
ίετ͔͔Δ͕ςετΛॻ͘ཧ༝͕͋Δ
ͦͦiOSΞϓϦ֎෦࿈ܞ͔Γ ࣗͨͪͷαʔόʔ ·ͨ8FC"1*Λެ։ͯ͘͠ΕͯΔ8FCαʔϏε ·ͨ'JSFCBTFͳͲͷαʔόʔϨεͳͲ "QQMFͷϑϨʔϜϫʔΫ ࣗͨͪͷιʔείʔυ 044ͷϑϨʔϜϫʔΫ Ӭଓσʔλʔ ʢ'JMFͱ͔%#ʣ ֤छ
ηϯαʔ 🤖 🐲
ͦͦiOSΞϓϦ֎෦࿈ܞ͔Γ ࣗͨͪͷαʔόʔ ·ͨ8FC"1*Λެ։ͯ͘͠ΕͯΔ8FCαʔϏε ·ͨ'JSFCBTFͳͲͷαʔόʔϨεͳͲ "QQMFͷϑϨʔϜϫʔΫ ࣗͨͪͷιʔείʔυ 044ͷϑϨʔϜϫʔΫ ʮͤΊͯࣗͷॻ͍ͨίʔυݫີʹৼΔ͏Α͏ʹ͍ͨ͠ʯ Ӭଓσʔλʔ ʢ'JMFͱ͔%#ʣ
֤छ ηϯαʔ 🤖 🐲
ͦͦiOSΞϓϦ֎෦࿈ܞ͔Γ ࣗͨͪͷαʔόʔ ·ͨ8FC"1*Λެ։ͯ͘͠ΕͯΔ8FCαʔϏε ·ͨ'JSFCBTFͳͲͷαʔόʔϨεͳͲ "QQMFͷϑϨʔϜϫʔΫ ࣗͨͪͷιʔείʔυ 044ͷϑϨʔϜϫʔΫ ʮͤΊͯࣗͷॻ͍ͨίʔυݫີʹৼΔ͏Α͏ʹ͍ͨ͠ʯ Ӭଓσʔλʔ ʢ'JMFͱ͔%#ʣ
֤छ ηϯαʔ ʮUIͷૢ࡞͕લఏͳΒࢮ͵΄Ͳखಈςετͨ͠ΒΧόʔͰ͖Δͷʹ…ʯ 🤖 🐲
ͪΖΜ ͲΜͳςετͰॻ͚ྑ͍Θ͚Ͱͳ͘ ѱ͍ςετΛॻ͍͍͚ͯͳ͍
ྑ͍ςετͷରଆʹ͋Δѱ͍ςετ • ཧղͮ͠Β͍ςετίʔυ • ඞཁҎ্ʹ͍ςετίʔυ • յΕ͍͢ςετ • ςετ݁Ռ͕ෆ҆ఆͳςετ 🐲
ྑ͍ςετͷରଆʹ͋Δѱ͍ςετ • ཧղͮ͠Β͍ςετίʔυ • ඞཁҎ্ʹ͍ςετίʔυ • յΕ͍͢ςετ • ςετ݁Ռ͕ෆ҆ఆͳςετ ʮෆ҆ఆͳςετ݁ՌʹͳΔͱ։ൃऀͷʹཱͨͳ͍͕େ͖͍ʯ
🐲
ຊ ෆ҆ఆͳςετͷݪҼΛཧ͠ղܾ͢Δ
ࢲͷʮෆ҆ఆͳςετʯͷఆٛ 100%ޭ 100%ࣦഊ ಉҰͷςετίʔυͰ ޭͨ͠Γࣦഊͨ͠Γ ݁Ռ͕ෆ҆ఆ 🤖 🐲
ࢲͷʮෆ҆ఆͳςετʯͷఆٛ 100%ޭ 100%ࣦഊ ಉҰͷςετίʔυͰ ޭͨ͠Γࣦഊͨ͠Γ ݁Ռ͕ෆ҆ఆ ʮFlakyʢ৴པͰ͖ͳ͍ʣςετͬͯݴ͍͍͑ͷʹ…ʯ 🤖 🐲
ࢲͷʮෆ҆ఆͳςετʯͷఆٛ 100%ޭ 100%ࣦഊ ಉҰͷςετίʔυͰ ޭͨ͠Γࣦഊͨ͠Γ ݁Ռ͕ෆ҆ఆ ʮFlakyʢ৴པͰ͖ͳ͍ʣςετͬͯݴ͍͍͑ͷʹ…ʯ ʮ݁Ռ͕ෆ҆ఆͱ͍͏ํ͕తͰ͖ʯ 🤖 🐲
ࠓճ͢ෆ҆ఆͳςετͷݪҼྨ • ݪҼ • ݪҼ1:࣮ߦॱংʹґଘ͢Δςετ • ݪҼ2: ࣮ߦ࣌·Ͱ͕ܾఆ͠ͳ͍࠶ݱੑͷͳ͍ςετ • ݪҼ3:
ϑϨʔϜϫʔΫཧղෆ • ݪҼ͕ද໘Խ͍͢͠: • CIͳͲͷςετ࣮ߦϚγϯͷϦιʔεෆ Swift 5.10Ͱݕূ
ݪҼ1: ࣮ߦॱংʹґଘ͢Δςετ • ྫ • ςετίʔυؒͰڞ༗ͷ/ࢀরΛ࣋ͬͯ͠·͏
ෆ҆ఆͳݪҼ: ࣮ߦॱংʹґଘ͢Δςετ class Singleton { static let shared = Singleton()
private init() {} var value: Int = 0 var unit: String = "g" } ———————————————————————-———————————————————————- final class SampleTests: XCTestCase { func test_value͕1000Ͱunit͕g_1000gͱදࣔ͞ΕΔ() { Singleton.shared.value = 1000 ɹɹɹɹ // ͜͜Ͱೖ͠Θ͢Ε͍ͯΔ͕ॳظ͕Χόʔͯ͠͠·ͬͯΔ XCTAssertEqual(Singleton.shared.value, 1000) XCTAssertEqual(Singleton.shared.unit, “g") // ԼͷςετΑΓઌʹ࣮ߦ͞ΕΔͱॳظ͕ΘΕςετޭ } func test_value1Ͱunit͕kg_1kgͱදࣔ͞ΕΔ() { Singleton.shared.value = 1 Singleton.shared.unit = "kg" XCTAssertEqual(Singleton.shared.value, 1) XCTAssertEqual(Singleton.shared.unit, "kg") } } 🐲 🤖
ෆ҆ఆͳݪҼ: ࣮ߦॱংʹґଘ͢Δςετ class Singleton { static let shared = Singleton()
private init() {} var value: Int = 0 var unit: String = "g" } ———————————————————————-———————————————————————- final class SampleTests: XCTestCase { func test_value͕1000Ͱunit͕g_1000gͱදࣔ͞ΕΔ() { Singleton.shared.value = 1000 ɹɹɹɹ // ͜͜Ͱೖ͠Θ͢Ε͍ͯΔ͕ॳظ͕Χόʔͯ͠͠·ͬͯΔ XCTAssertEqual(Singleton.shared.value, 1000) XCTAssertEqual(Singleton.shared.unit, “g") // ԼͷςετΑΓઌʹ࣮ߦ͞ΕΔͱॳظ͕ΘΕςετޭ } func test_value1Ͱunit͕kg_1kgͱදࣔ͞ΕΔ() { Singleton.shared.value = 1 Singleton.shared.unit = "kg" XCTAssertEqual(Singleton.shared.value, 1) XCTAssertEqual(Singleton.shared.unit, "kg") } } ʮγϯάϧτϯͳΜͯ Θͳ͚Ε͍͍ͷʹ…ʯ 🐲 🤖
ෆ҆ఆͳݪҼ: ࣮ߦॱংʹґଘ͢Δςετ class Singleton { static let shared = Singleton()
private init() {} var value: Int = 0 var unit: String = "g" } ———————————————————————-———————————————————————- final class SampleTests: XCTestCase { func test_value͕1000Ͱunit͕g_1000gͱදࣔ͞ΕΔ() { Singleton.shared.value = 1000 ɹɹɹɹ // ͜͜Ͱೖ͠Θ͢Ε͍ͯΔ͕ॳظ͕Χόʔͯ͠͠·ͬͯΔ XCTAssertEqual(Singleton.shared.value, 1000) XCTAssertEqual(Singleton.shared.unit, “g") // ԼͷςετΑΓઌʹ࣮ߦ͞ΕΔͱॳظ͕ΘΕςετޭ } func test_value1Ͱunit͕kg_1kgͱදࣔ͞ΕΔ() { Singleton.shared.value = 1 Singleton.shared.unit = "kg" XCTAssertEqual(Singleton.shared.value, 1) XCTAssertEqual(Singleton.shared.unit, "kg") } } ʮγϯάϧτϯͳΜͯ Θͳ͚Ε͍͍ͷʹ…ʯ ʮ͜͏͍͏߹setUp() ΛͬͯॳظԽʯ 🐲 🤖
ෆ҆ఆͳݪҼ: ࣮ߦॱংʹґଘ͢Δςετ 🐲 ʮͪͳΈʹɺXCTestCaseͷϓϩύςΟࣗಈͰॳظԽ͞Ε·͢ʯ 🤖 🐲
ෆ҆ఆͳݪҼ: ࣮ߦॱংʹґଘ͢Δςετ 🐲 ʮͪͳΈʹɺXCTestCaseͷϓϩύςΟࣗಈͰॳظԽ͞Ε·͢ʯ ʮclassͳͷͰ༧͔ͭͳ͍ ͷͰ͓͢͢ΊͰ͖ͳ͍…ʯ 🤖 🐲
ෆ҆ఆͳݪҼ: ࣮ߦॱংʹґଘ͢Δςετ 🐲 ʮͪͳΈʹɺXCTestCaseͷϓϩύςΟࣗಈͰॳظԽ͞Ε·͢ʯ ʮclassͳͷͰ༧͔ͭͳ͍ ͷͰ͓͢͢ΊͰ͖ͳ͍…ʯ 🤖 ʮ࣍ੈͷSwift Testing Ͱ
ͨΓલʹͳΓ·͢Αʯ 🐲
ݪҼ2: ࣮ߦ࣌ʹ͕ܾఆ͢Δಈతͳॲཧͷςετ • ྫ • Date() / Date.init() / Date.now
• ݺͼग़͞Εͨࡍͷ࣌ؒΛऔಘ͢Δίʔυ
class TimeUtils { // ࠓճͷςετର // ݱࡏ࣌ࠁ͔ΒҾͷDateͱͷࠩΛTimeintervalͰฦ͢ϝιου func timeElapsedSince(_ date:
Date) -> TimeInterval { Date().timeIntervalSince(date) } } ———————————————————————-———————————————————————————————————————- final class TimeUtilsTests: XCTestCase { let timeUtils = TimeUtils() func test_TimeElapsedSince() { let date = Date(timeIntervalSinceNow: -6) // 6ඵલͷDate // Action …….. ͜͜Βล͕ΊͪΌͪ͘Ό͔͔࣌ؒͬͨΒఆ͔ΒͣΕΔ let elapsed = timeUtils.timeElapsedSince(date) // Assertion XCTAssertEqual( elapsed, 6, accuracy: 0.1 // ڐ༰͢Δޡࠩൣғ ) } } ෆ҆ఆͳݪҼ: ࣮ߦ࣌ʹ͕ܾఆ͢Δಈతͳॲཧͷςετ 🤖
class TimeUtils { // ࠓճͷςετର // ݱࡏ࣌ࠁ͔ΒҾͷDateͱͷࠩΛTimeintervalͰฦ͢ϝιου func timeElapsedSince(_ date:
Date) -> TimeInterval { Date().timeIntervalSince(date) } } ———————————————————————-———————————————————————————————————————- final class TimeUtilsTests: XCTestCase { let timeUtils = TimeUtils() func test_TimeElapsedSince() { let date = Date(timeIntervalSinceNow: -6) // 6ඵલͷDate // Action …….. ͜͜Βล͕ΊͪΌͪ͘Ό͔͔࣌ؒͬͨΒఆ͔ΒͣΕΔ let elapsed = timeUtils.timeElapsedSince(date) // Assertion XCTAssertEqual( elapsed, 6, accuracy: 0.1 // ڐ༰͢Δޡࠩൣғ ) } } ෆ҆ఆͳݪҼ: ࣮ߦ࣌ʹ͕ܾఆ͢Δಈతͳॲཧͷςετ ʮݱࡏ࣌ࠁʹཔΔͱςετ ɹ͢ΔCIͷϚγϯύϫʔʹ ɹґଘ͢Δͷʹ…ʯ 🤖
class TimeUtils { func timeElapsedSince(date: Date, currentDate: Date = Date())
-> TimeInterval { // ςετ͢Δରͷॲཧ࣮ߦ࣌ʹܾ·Βͳ͍Α͏ʹ͠࠶ݱੑΛߴΊΔ currentDate.timeIntervalSince(date) } } ———————————————————————-———————————————————————-———————————————————————- final class TimeUtilsTests: XCTestCase { let timeUtils = TimeUtils() // ࠓճͷςετର func test_TimeElapsedSince2() { let currentDate = Date(timeIntervalSince1970: 0) // 1970/1/1ͷ0࣌ let date = Date(timeIntervalSince1970: -6) // 1970/1/1ͷ0͔࣌Β6ඵલ // Action let elapsed = timeUtils.timeElapsedSince( date: date, currentDate: currentDate ) // Assertion ɹ XCTAssertEqual( elapsed, 6, accuracy: 0.1 // ڐ༰͢Δޡࠩൣғ ) } } ෆ҆ఆͳݪҼ: ࣮ߦ࣌ʹ͕ܾఆ͢Δಈతͳॲཧͷςετ
ิ: ࣮ߦ࣌ʹಈతʹ͕ܾఆ͢ΔͭΒ • Foundation.Date / Calendar / Locale / UUID
• ͳͲͷཚੜ https://github.com/pointfreeco/swift-dependencies/tree/main/ Sources/Dependencies/DependencyValues ࢀߟ: pointfreeco/swift-dependencies ෆ҆ఆͳݪҼ: ࣮ߦ࣌ʹ͕ܾఆ͢Δಈతͳॲཧͷςετ
ݪҼ3: OSSϑϨʔϜϫʔΫཧղෆ • ྫ • ҙਤͤͣRealm͕εϨουؒΛӽ͑ͯ͠·͏ • ผεϨουͰRealmͷ݁ՌΛrefreshͤͣݕূͯ͠͠·͏
ෆ҆ఆͳݪҼ:OSSϑϨʔϜϫʔΫཧղෆ https://developer.apple.com/documentation/xctest/asynchronous_tests_and_expectations جૅ: XCTestͷglobalActorࢦఆ༗ແͷڍಈͷҧ͍ 🤖 🐲 🐲
ෆ҆ఆͳݪҼ:OSSϑϨʔϜϫʔΫཧղෆ https://developer.apple.com/documentation/xctest/asynchronous_tests_and_expectations ʮMainActorࢦఆ ɹϝΠϯεϨουʯ جૅ: XCTestͷglobalActorࢦఆ༗ແͷڍಈͷҧ͍ 🤖 🐲 🐲
ෆ҆ఆͳݪҼ:OSSϑϨʔϜϫʔΫཧղෆ https://developer.apple.com/documentation/xctest/asynchronous_tests_and_expectations ʮMainActorࢦఆ ɹϝΠϯεϨουʯ ʮແࢦఆϝΠϯ ɹεϨουͰͳ͍ʯ جૅ: XCTestͷglobalActorࢦఆ༗ແͷڍಈͷҧ͍ 🤖 🐲
🐲
ෆ҆ఆͳݪҼ:OSSϑϨʔϜϫʔΫཧղෆ https://developer.apple.com/documentation/xctest/asynchronous_tests_and_expectations ʮMainActorࢦఆ ɹϝΠϯεϨουʯ ʮແࢦఆϝΠϯ ɹεϨουͰͳ͍ʯ جૅ: XCTestͷglobalActorࢦఆ༗ແͷڍಈͷҧ͍ ʮެࣜυΩϡϝϯτʹॻ͔ΕͯΔͷʹ…ʯ 🤖
🐲 🐲
@globalActor actor DBActor { static let shared = DBActor() }
class ThreadTests2: XCTestCase { // MainActorʢglobalActorࢦఆʣແ͠ func test_MainActorͰͳ͘async() async { print("A:", Thread.current) let task = Task { @DBActor in try! await Task.sleep(nanoseconds: 1_000_000_000 * 5) print("B:", Thread.current) } await task.value print("C:", Thread.current) } } ෆ҆ఆͳݪҼ:OSSϑϨʔϜϫʔΫཧղෆ جૅ: globalActorࢦఆແ͠ͰActorݺͼग़͢ͱ࣮ߦ εϨουঢ়گʹࠨӈ͞ΕΔʢεϨουϓʔϧ͔ΒબΕΔʣ 🐲
@globalActor actor DBActor { static let shared = DBActor() }
class ThreadTests2: XCTestCase { // MainActorʢglobalActorࢦఆʣແ͠ func test_MainActorͰͳ͘async() async { print("A:", Thread.current) let task = Task { @DBActor in try! await Task.sleep(nanoseconds: 1_000_000_000 * 5) print("B:", Thread.current) } await task.value print("C:", Thread.current) } } ෆ҆ఆͳݪҼ:OSSϑϨʔϜϫʔΫཧղෆ جૅ: globalActorࢦఆແ͠ͰActorݺͼग़͢ͱ࣮ߦ εϨουঢ়گʹࠨӈ͞ΕΔʢεϨουϓʔϧ͔ΒબΕΔʣ 🐲
@globalActor actor DBActor { static let shared = DBActor() }
class ThreadTests2: XCTestCase { // MainActorʢglobalActorࢦఆʣແ͠ func test_MainActorͰͳ͘async() async { print("A:", Thread.current) let task = Task { @DBActor in try! await Task.sleep(nanoseconds: 1_000_000_000 * 5) print("B:", Thread.current) } await task.value print("C:", Thread.current) } } ෆ҆ఆͳݪҼ:OSSϑϨʔϜϫʔΫཧղෆ εϨουA,B,CͷՄೳੑ A == B, B== C || A == B, B!= C || A != B, B== C || A == C, C !== B || جૅ: globalActorࢦఆແ͠ͰActorݺͼग़͢ͱ࣮ߦ εϨουঢ়گʹࠨӈ͞ΕΔʢεϨουϓʔϧ͔ΒબΕΔʣ 🐲
ෆ҆ఆͳݪҼ:OSSϑϨʔϜϫʔΫཧղෆ ྫ: ҙਤͤͣRealm͕εϨουؒΛӽ͑ͯ͠·͏ 🐲 @globalActor actor DBActor { static let
shared = DBActor() } class ThreadTests2: XCTestCase { // MainActorʢglobalActorࢦఆʣແ͠ func test_MainActorͰͳ͘async() async { print("A:", Thread.current) let otherRealm = RLMRealm.default() let task = Task { @DBActor in try! await Task.sleep(nanoseconds: 1_000_000_000 * 5) print("B:", Thread.current) } await task.value print("C:", Thread.current) XCTAssertNotNil( RealmObject.object(in: otherRealm, forPrimaryKey: "1") ) } } 🐲
ෆ҆ఆͳݪҼ:OSSϑϨʔϜϫʔΫཧղෆ ྫ: ҙਤͤͣRealm͕εϨουؒΛӽ͑ͯ͠·͏ 🐲 @globalActor actor DBActor { static let
shared = DBActor() } class ThreadTests2: XCTestCase { // MainActorʢglobalActorࢦఆʣແ͠ func test_MainActorͰͳ͘async() async { print("A:", Thread.current) let otherRealm = RLMRealm.default() let task = Task { @DBActor in try! await Task.sleep(nanoseconds: 1_000_000_000 * 5) print("B:", Thread.current) } await task.value print("C:", Thread.current) XCTAssertNotNil( RealmObject.object(in: otherRealm, forPrimaryKey: "1") ) } } 🐲
ෆ҆ఆͳݪҼ:OSSϑϨʔϜϫʔΫཧղෆ ྫ: ҙਤͤͣRealm͕εϨουؒΛӽ͑ͯ͠·͏ 🐲 @globalActor actor DBActor { static let
shared = DBActor() } class ThreadTests2: XCTestCase { // MainActorʢglobalActorࢦఆʣແ͠ func test_MainActorͰͳ͘async() async { print("A:", Thread.current) let otherRealm = RLMRealm.default() let task = Task { @DBActor in try! await Task.sleep(nanoseconds: 1_000_000_000 * 5) print("B:", Thread.current) } await task.value print("C:", Thread.current) XCTAssertNotNil( RealmObject.object(in: otherRealm, forPrimaryKey: "1") ) } } 🐲
ෆ҆ఆͳݪҼ:OSSϑϨʔϜϫʔΫཧղෆ ྫ: ҙਤͤͣRealm͕εϨουؒΛӽ͑ͯ͠·͏ 🐲 @globalActor actor DBActor { static let
shared = DBActor() } class ThreadTests2: XCTestCase { // MainActorʢglobalActorࢦఆʣແ͠ func test_MainActorͰͳ͘async() async { print("A:", Thread.current) let otherRealm = RLMRealm.default() let task = Task { @DBActor in try! await Task.sleep(nanoseconds: 1_000_000_000 * 5) print("B:", Thread.current) } await task.value print("C:", Thread.current) XCTAssertNotNil( RealmObject.object(in: otherRealm, forPrimaryKey: "1") ) } } 🐲
ෆ҆ఆͳݪҼ:OSSϑϨʔϜϫʔΫཧղෆ εϨουA==Cͷ߹ RealmಉҰεϨουͰར༻ ✅ ޭ ྫ: ҙਤͤͣRealm͕εϨουؒΛӽ͑ͯ͠·͏ 🐲 @globalActor actor
DBActor { static let shared = DBActor() } class ThreadTests2: XCTestCase { // MainActorʢglobalActorࢦఆʣແ͠ func test_MainActorͰͳ͘async() async { print("A:", Thread.current) let otherRealm = RLMRealm.default() let task = Task { @DBActor in try! await Task.sleep(nanoseconds: 1_000_000_000 * 5) print("B:", Thread.current) } await task.value print("C:", Thread.current) XCTAssertNotNil( RealmObject.object(in: otherRealm, forPrimaryKey: "1") ) } } 🐲
ෆ҆ఆͳݪҼ:OSSϑϨʔϜϫʔΫཧղෆ εϨουA==Cͷ߹ RealmಉҰεϨουͰར༻ ✅ ޭ ྫ: ҙਤͤͣRealm͕εϨουؒΛӽ͑ͯ͠·͏ 🐲 @globalActor actor
DBActor { static let shared = DBActor() } class ThreadTests2: XCTestCase { // MainActorʢglobalActorࢦఆʣແ͠ func test_MainActorͰͳ͘async() async { print("A:", Thread.current) let otherRealm = RLMRealm.default() let task = Task { @DBActor in try! await Task.sleep(nanoseconds: 1_000_000_000 * 5) print("B:", Thread.current) } await task.value print("C:", Thread.current) XCTAssertNotNil( RealmObject.object(in: otherRealm, forPrimaryKey: "1") ) } } εϨουA != Cͷ߹ Realm͕ผεϨουͰར༻͞ΕΔ 🚫 ࣦഊ 🐲
ෆ҆ఆͳݪҼ:OSSϑϨʔϜϫʔΫཧղෆ ྫ: ผεϨουͷRealmͷॻ͖ࠐΈΛ͚ͭͩͰ ·ͩಉظ͍ྃͯ͠ͳ͍ ಉظλΠϛϯά खಈSFGSFTI ·ͨ࣌ؒܦա ·ͨ BVUPSFGSFTIʢϝΠϯεϨουͷσϑΥϧτʣ ·ͨ
͓ͦΒͦ͘ͷଞ͍Ζ͍ΖͳλΠϛϯά ͦΕͱผ εϨουͷ Realm ผεϨουͷ Realm 🐲
ෆ҆ఆͳݪҼ:OSSϑϨʔϜϫʔΫཧղෆ ྫ: ผεϨουͷRealmͷॻ͖ࠐΈΛ͚ͭͩͰ ·ͩಉظ͍ྃͯ͠ͳ͍ ಉظλΠϛϯά खಈSFGSFTI ·ͨ࣌ؒܦա ·ͨ BVUPSFGSFTIʢϝΠϯεϨουͷσϑΥϧτʣ ·ͨ
͓ͦΒͦ͘ͷଞ͍Ζ͍ΖͳλΠϛϯά ͦΕͱผ εϨουͷ Realm ผεϨουͷ Realm Realmͷॻ͖ࠐΈΛݕূ͢Δ݁Ռ͕ ෆ҆ఆͳͱ͖ ಈ࡞͍ͯ͠ΔεϨουΛௐࠪ͠ɺ RealmͷυΩϡϝϯτͰ realm.refresh()ΛௐͯΈ͍ͨɻ 🐲
·ͱΊ
ෆ҆ఆͳ݁Ռͷ࣌ʹؾ͕͖͍ͭͨ͜ͱ • ςετέʔεؒͰ/ࢀরΛ࠶ར༻ͯ͠ͳ͍͔ • ಈతʹܾ·ΔΛϩδοΫςετίʔυʹຒΊࠐΜͰ͍ͳ͍͔ • ࣮ߦεϨου͕ҙਤͤͣมΘͬͯ͠·͍ͬͯͳ͍͔
͓ΘΓʹ
ͦͷ΄͔ͷෆ҆ఆͷݪҼͱղܾͷ • ࠓճઆ໌লུʢผͷࢿྉ: ෆ҆ఆͳςετ200छྨ͋ΜͶΜʣ • https://speakerdeck.com/yimajo/bu-an-ding-natesutoha200zhong- lei-annen
͜ͷൃදͰ ؒҧ͍͕͋ͬͨΓ͝ҙݟ͋Εɺ ͳΔ͘ Θ͔Γ͘͢ࢦఠ࣭͚ͯ͠Δͱ ༗ҙٛͳΓͱΓ͕Ͱ͖ΔͣͰ͢ɻ ʢࢲͷࢥ͍ࠐΈͰղܾͨͭ͠Γʹͳ͍ͬͯΔ͜ͱ͋Γ·͢ʣ
͓ΘΓ 🐲 🤖 ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠