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.9k
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
390
OSSとなったswift-buildで Xcodeのビルドを差し替えられるため 自分でXcodeを直せる時代になっている ダイアモンド問題編
yimajo
3
930
いま中途半端なSwift 6対応をするより、Default ActorやApproachable Concurrencyを有効にしてからでいいんじゃない?
yimajo
2
750
11年かかって やっとVibe Codingに 時代が追いつきましたね
yimajo
1
410
iOSアプリ開発で 関数型プログラミングを実現する The Composable Architectureの紹介
yimajo
3
360
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
Intent as Code
shoppingjaws
6
1.1k
Agents on Rails - Rails at Scale 2026
irinanazarova
0
320
カツオ、ご期待ください
suneo3476
0
140
Security issues being discussed on Web Platforms
petamoriken
0
1.4k
AGENTS.md Is Not Enough:Build Skills, Don't Download Them
lx_t
0
130
Java 27新機能 / Java 27 new features
kishida
2
190
C#の現在地 進化の歴史と、AI時代の.NET Everywhere
neuecc
5
4.8k
APNsからLive Activityを開始する話
yumnumm
0
150
MVNOの申込からeSIM開通までをiOSアプリでつなぐ- 本人確認・MNP・通信事業者基盤をまたぐ実装
satotakeshi
0
530
WebRTC映像をAirPlayに対応させる挑戦.pdf
monolithic_adam
0
330
テストを司るデーモンに会いに行く 〜隔離した仮想マシンでテストを通すまで〜
h1d3mun3
1
600
スマートフォンでモールス信号を送受信する 〜スマートフォンのLEDとカメラで作る光通信の設計と実装〜
atsuki_seo
0
230
Featured
See All Featured
From π to Pie charts
rasagy
1
390
Navigating Team Friction
lara
192
16k
Designing for Timeless Needs
cassininazir
1
520
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
420
So, you think you're a good person
axbom
PRO
2
2.2k
Faster Mobile Websites
deanohume
310
32k
The Cult of Friendly URLs
andyhume
79
7k
Neural Spatial Audio Processing for Sound Field Analysis and Control
skoyamalab
0
540
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
260
Utilizing Notion as your number one productivity tool
mfonobong
4
610
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.9k
Reflections from 52 weeks, 52 projects
jeffersonlam
356
21k
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
͜ͷൃදͰ ؒҧ͍͕͋ͬͨΓ͝ҙݟ͋Εɺ ͳΔ͘ Θ͔Γ͘͢ࢦఠ࣭͚ͯ͠Δͱ ༗ҙٛͳΓͱΓ͕Ͱ͖ΔͣͰ͢ɻ ʢࢲͷࢥ͍ࠐΈͰղܾͨͭ͠Γʹͳ͍ͬͯΔ͜ͱ͋Γ·͢ʣ
͓ΘΓ 🐲 🤖 ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠