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
サバンナ便り〜自動テストに関する連載で得られた知見のまとめ〜
Search
Takuto Wada
PRO
March 03, 2023
Programming
19
8.9k
サバンナ便り〜自動テストに関する連載で得られた知見のまとめ〜
2023/03/03(金)
Forkwell エンジニア文化祭 2023
Takuto Wada
PRO
March 03, 2023
Tweet
Share
More Decks by Takuto Wada
See All by Takuto Wada
予防に勝る防御なし(2025年版) - 堅牢なコードを導く様々な設計のヒント / Growing Reliable Code PHP Conference Fukuoka 2025
twada
PRO
46
24k
SQLアンチパターン第2版 データベースプログラミングで陥りがちな失敗とその対策 / Intro to SQL Antipatterns 2nd
twada
PRO
45
34k
AI時代のソフトウェア開発を考える(2025/07版) / Agentic Software Engineering Findy 2025-07 Edition
twada
PRO
187
110k
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
115
100k
The Clean ArchitectureがWebフロントエンドでしっくりこないのは何故か / Why The Clean Architecture does not fit with Web Frontend
twada
PRO
85
44k
組織に自動テストを書く文化を根付かせる戦略(2024冬版) / Building Automated Test Culture 2024 Winter Edition
twada
PRO
37
14k
ピラミッド、アイスクリームコーン、SMURF: 自動テストの最適バランスを求めて / Pyramid Ice-Cream-Cone and SMURF
twada
PRO
10
3.1k
組織に自動テストを書く文化を根付かせる戦略(2024秋版) / Building Automated Test Culture 2024 Autumn Edition
twada
PRO
15
7.3k
これまでと違う学び方をしたら挫折せずにRustを学べた話 / Programming Rust techramen24conf LT
twada
PRO
36
31k
Other Decks in Programming
See All in Programming
例外処理とどう使い分ける?Result型を使ったエラー設計 #burikaigi
kajitack
16
5.3k
Graviton と Nitro と私
maroon1st
0
160
Python札幌 LT資料
t3tra
7
1.1k
AI時代を生き抜く 新卒エンジニアの生きる道
coconala_engineer
1
530
ZJIT: The Ruby 4 JIT Compiler / Ruby Release 30th Anniversary Party
k0kubun
1
330
Giselleで作るAI QAアシスタント 〜 Pull Requestレビューに継続的QAを
codenote
0
340
JETLS.jl ─ A New Language Server for Julia
abap34
2
480
ELYZA_Findy AI Engineering Summit登壇資料_AIコーディング時代に「ちゃんと」やること_toB LLMプロダクト開発舞台裏_20251216
elyza
2
1.1k
メルカリのリーダビリティチームが取り組む、AI時代のスケーラブルな品質文化
cloverrose
2
470
re:Invent 2025 トレンドからみる製品開発への AI Agent 活用
yoskoh
0
630
Denoのセキュリティに関する仕組みの紹介 (toranoana.deno #23)
uki00a
0
230
AI Agent の開発と運用を支える Durable Execution #AgentsInProd
izumin5210
7
1.7k
Featured
See All Featured
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
550
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
0
3.4k
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
86
The SEO Collaboration Effect
kristinabergwall1
0
330
Ruling the World: When Life Gets Gamed
codingconduct
0
120
Documentation Writing (for coders)
carmenintech
77
5.2k
Rails Girls Zürich Keynote
gr2m
95
14k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
249
1.3M
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
140
Code Reviewing Like a Champion
maltzj
527
40k
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
1
360
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
290
Transcript
ాਓʢ!U@XBEBʣ αόϯφศΓ ࣗಈςετʹؔ͢Δ࿈ࡌͰಘΒΕͨݟͷ·ͱΊ 📷🙆 🙆 'PSLXFMMจԽࡇ@" .BS
t-wada t_wada twada 📷🙆 📹🙅 🙆 ࣗݾհ #Forkwell文化祭_A
ٕज़ॻͷग़൛ʹؔΘ͍ͬͯ·͢
αόϯφศΓʜʜʁ
IUUQTUXBEBIBUFOBCMPHKQFOUSZXEQSFTTTBWBOOBDPMVNO 8&# %#13&44ʹίϥϜΛ࿈ࡌ͍ͯ͠·͢
IUUQTUXBEBIBUFOBCMPHKQFOUSZXEQSFTTTBWBOOBDPMVNO 8&# %#13&44ʹίϥϜΛ࿈ࡌ͍ͯ͠·͢
ΑΖ͓͘͠ئ͍͠·͢ 📷🙆 🙆 'PSLXFMMจԽࡇ@"
"HFOEB࿈ࡌ֤ճͷςʔϚ ֶश༻ςετ ِཅੑͱِӄੑ ςεταΠζ ςετμϒϧ ςετϐϥϛου 🦁
ֶͼΛࣗಈςετͱͯ͠ॻ͘ ଈ࣌ੑͱ࠶ݱੑ
ֶशྫ1)1ͷ%BUF5JNFͱ%BUF5JNF*NNVUBCMF IUUQTXXXQIQOFUNBOVBMKBDMBTTEBUFUJNFJNNVUBCMFQIQ
/** * @test * @group learning */ public function DateTimeのaddは自身の状態を変更しつつ自身を返す():
void { $halloween = new \DateTime('2021-10-31'); $oneYear = \DateInterval::createFromDateString('1 year'); $halloween2022 = $halloween->add($oneYear); $this->assertSame($halloween, $halloween2022); $this->assertEquals('2022-10-31', $halloween->format('Y-m-d')); $this->assertEquals('2022-10-31', $halloween2022->format('Y-m-d')); } /** * @test * @group learning */ public function DateTimeImmutableのaddは自身の状態を変更せず新しい状態を伴う新しいインスタンスを返す(): void { $halloween = new \DateTimeImmutable('2021-10-31'); $oneYear = \DateInterval::createFromDateString('1 year'); $halloween2022 = $halloween->add($oneYear); $this->assertNotSame($halloween, $halloween2022); $this->assertEquals('2021-10-31', $halloween->format('Y-m-d')); $this->assertEquals('2022-10-31', $halloween2022->format('Y-m-d')); } %BUF5JNFͱ%BUF5JNF*NNVUBCMFͷҧ͍Λֶशςετʹ͢Δ ֶशςετʢֶͼ͕తͷςετʣΛ ݟ͚ΔͨΊʹ MFBSOJOHλάΛ͚͍ͭͯ·͢ ֶ͕͜͜ͼ ֶ͕͜͜ͼ
ٙΛςετʹ͢Δ
/** * @test * @group learning */ public function 同じ時刻を指している場合はタイムゾーンが異なっても等価とみなされる():
void { $utc = new DateTimeImmutable('2021-12-24T15:00:00', new DateTimeZone('UTC')); $jst = new DateTimeImmutable('2021-12-25T00:00:00', new DateTimeZone('Asia/Tokyo')); $this->assertTrue($utc == $jst); } ٙΛςετʹ͢Δ ςετʹฉ͍ͯΈΕ͍͍
ڻ͖Λςετʹ͢Δ ྫ͑ʜʜ
ί ϯ ε τ ϥ Ϋ λ
Ұ ճ ͠ ͔ ݺ ͳ ͍ ͱ ࡨ ֮ ͠ ͯ ͍ ͨ ʁ ㅟ ㅟ ㅟ ㅟ ㅟ ㅟ ㅟ ㅟ ㅟ ㅟ ㅟ ㅟ ㅟ ㅟ ㅟ Ұ ମ ͍ ͭ ͔ Β
/** * @test * @group learning */ public function コンストラクタをもう一度呼ぶと破壊的変更ができてしまう():
void { $dt = new \DateTimeImmutable('2021-12-24'); $this->assertSame('2021-12-24', $dt->format('Y-m-d')); $dt->__construct('2022-01-01'); $this->assertSame('2022-01-01', $dt->format('Y-m-d')); } ͳΜʜʜͩͱʜʜʂʁ ໌ࣔతʹݺͯ͠·͏ ༨ஊ͜ͷςετίʔυΛ͖͔͚ͬʹQIQTSDʹJTTVFͱͯ͠ใࠂ͞Εɺ͕ٞߦΘΕ·ͨ͠ɻ IUUQTHJUIVCDPNQIQQIQTSDJTTVFT ༨ஊ͜ͷςετίʔυΛ͖͔͚ͬʹ੩తղੳπʔϧ1)14UBOͱ1TBMNʹػೳఏҊ͕ߦΘΕɺ 1)14UBOʹ!NVOP@͞Μ͕࡞ͨ͠QVMMSFRVFTU͕࠾༻͞ΕɺϦϦʔε͞Ε·ͨ͠ɻ IUUQTHJUIVCDPNQIQTUBOQIQTUBOTSDQVMM
"HFOEB࿈ࡌ֤ճͷςʔϚ ֶश༻ςετ ِཅੑͱِӄੑ ςεταΠζ ςετμϒϧ ςετϐϥϛου 🦁
ࣗಈςετͷ৴པੑΛ Ή͠ΉݱΛཧղ͢Δ
ςετࣗಈԽͱاۀͷۀͷҼՌؔ IUUQTXXXBNB[PODPKQEQ ςετͷࣗಈԽʹ͓͍ͯɺ*5ύϑΥʔϚϯεͷ༧ଌईͱͳΓ͏Δ ͜ͱ͕໌ͨ͠ͷ࣍ͷͭ ৴པੑͷߴ͍ࣗಈςετΛඋ͑Δ͜ͱ ։ൃऀओମͰड͚ೖΕςετΛ࡞ɾཧ͠ɺ खݩͷ։ൃڥͰ؆୯ʹ࠶ݱɾमਖ਼Ͱ͖Δ͜ͱ
ʰ-FBOͱ%FW0QTͷՊֶʱQʢ˞༁ΛҰ෦มߋʣ
IUUQTXXXBNB[PODPKQEQ ςετʹ߹֨ͨ͠ιϑτΣΞͰ͋ΕϦϦʔεՄೳɺෆ߹֨Ͱ͋Εॏେͳ ෆ۩߹͕͋ΔɺͱνʔϜ͕֬৴Ͱ͖ΔΑ͏ͳςετΛ࣮ࢪ͍ͯ͠Δ͜ͱ ޡݕʢِཅੑGBMTFQPTJUJWFʣݟಀ͠ʢِӄੑGBMTFOFHBUJWFʣ͕ଟ ͘ɺ৴པੑʹ͚ܽΔςετεΠʔτ͕͋·Γʹଟ͗͢Δ ৴པͷߴ͍ςετεΠʔτΛ࡞Γ্͛ΔܧଓతͳྗͱࢿՁ͕͋Δ ʰ-FBOͱ%FW0QTͷՊֶʱQʢ˞༁ΛҰ෦มߋʣ ৴པੑͷߴ͍ࣗಈςετΛඋ͑Δ͜ͱ
ِཅੑͱِӄੑ IUUQTHJIZPKQNBHB[JOFXEQSFTTBSDIJWFWPM
ِཅੑͱِӄੑͷύλʔϯ w ِཅੑ w ੬͍ςετ CSJUUMFUFTU GSBHJMFUFTU w ৴པෆೳςετ
fl BLZUFTU w ِӄੑ w ۭৼΓ w ΧόϨοδෆ w ςετରϩδοΫͷςετίʔυͷ࿙Εग़͠
// プロダクトコード class Item { // コンストラクタ割愛 tax_amount() { const
rate = (this.tax_rate / 100); return (this.price / (1 + rate)) * rate; } } // テストコード it('税込価格から税額を返す', () => { const item = new Item('技評茶', 130, 8); const expected = (130 / (1 + (8 / 100))) * (8 / 100); assert.equal(item.tax_amount(), expected); }); ྫςετରϩδοΫͷςετίʔυͷ࿙Εग़͠ ԁະຬͷ͕ൃੜ͢Δ όά͕͋Δ ςετίʔυͷํಉ͡ϩδοΫͰ ظΛܭࢉ͍ͯ͠ΔͷͰ ςετ͕ޭͯ͠͠·͏
৴པෆೳੑʢ fl BLJOFTTʣ͕ʹۙ͢ΔͱɺςετՁΛࣦ͍࢝ΊΔ IUUQTXXXPSFJMMZDPKQCPPLT ʰ(PPHMFͷιϑτΣΞΤϯδχΞϦϯάʱQ
"HFOEB࿈ࡌ֤ճͷςʔϚ ֶश༻ςετ ِཅੑͱِӄੑ ςεταΠζ ςετμϒϧ ςετϐϥϛου 🦁
ࣗಈςετͱ$*ʹϑΟοτ͢Δ ໌֬ͳςετྨج४
օ͞Μʹ͓͍͠·͢ 🙋🙋🙋 wσʔλϕʔεʹΞΫηε͢ΔͷϢχοτςετ :FT/P wωοτϫʔΫʹΞΫηε͢ΔͷϢχοτςετ :FT/P wϑΝΠϧʹΞΫηε͢ΔͷϢχοτςετ :FT/P wݱࡏ࣌ࠁʹΞΫηε͢ΔͷϢχοτςετ :FT/P
wґଘઌͷΫϥεʹຊΛ͏ͷϢχοτςετ :FT/P
IUUQTNBSUJOGPXMFSDPNCMJLJ6OJU5FTUIUNM 6OJU5FTUͷ6OJUͬͯԿʁ
5FTU4J[FΑΓᐆດ͞ͷগͳ͍ྨ
IUUQTUFTUJOHHPPHMFCMPHDPNUFTUTJ[FTIUNM 5FTU4J[F
4NBMM ʢ୯Ұϓϩηεʣ .FEJVN ʢ୯ҰϚγϯʣ -BSHF ʢ੍ͳ͠ʣ 6OJU
ൺ େ͍ʹਪ ආ͚͍͕ͨ ͔ͨ͠ͳ͍ͱ͖ ࠷ѱ͕ͩ Α͘ݟ͔͚Δ *OUFHSBUJPO ൺ ॻ͚ΔͳΒ ίεύྑ͠ ී௨ Ͱ͖Ε ආ͚͍ͨ && ൺ ݪཧ্ෆՄೳʹ͍͕ۙ খ͍͞γεςϜͳΒՄೳʁ খ͍͞γεςϜ ͳΒՄೳ ී௨͔ͭ $6+ʹߜΓ͍ͨ 5FTU4DPQF 5FTU4J[F 5FTU4DPQFͱ5FTU4J[F
4NBMM ʢ୯Ұϓϩηεʣ .FEJVN ʢ୯ҰϚγϯʣ -BSHF ʢ੍ͳ͠ʣ 6OJU
ൺ େ͍ʹਪ ආ͚͍͕ͨ ͔ͨ͠ͳ͍ͱ͖ ࠷ѱ͕ͩ Α͘ݟ͔͚Δ *OUFHSBUJPO ൺ ॻ͚ΔͳΒ ίεύྑ͠ ී௨ Ͱ͖Ε ආ͚͍ͨ && ൺ ݪཧ্ෆՄೳʹ͍͕ۙ খ͍͞γεςϜͳΒՄೳʁ খ͍͞γεςϜ ͳΒՄೳ ී௨͔ͭ $6+ʹߜΓ͍ͨ 5FTU4DPQF 5FTU4J[F 5FTU4DPQFͱ5FTU4J[F ίεύྑ͠ ίεύѱ͠
"HFOEB࿈ࡌ֤ճͷςʔϚ ֶश༻ςετ ِཅੑͱِӄੑ ςεταΠζ ςετμϒϧ ςετϐϥϛου 🦁
࣮ੑͱܾఆੑͷ τϨʔυΦϑΛཧղ͢Δ
IUUQYVOJUQBUUFSOTDPN5FTU%PVCMFIUNM 5FTU%PVCMFࣗಈςετ༻ͷِ
IUUQYVOJUQBUUFSOTDPN5FTU%PVCMFIUNM 5FTU%PVCMFͷྨʢ࿈ࡌͷϖʔδʹऩ·Βͣʜʜʣ
ςετμϒϧͷརͱҙ IUUQTXXXBNB[PODPKQEQ w ར w ςετ͠ʹ͍͘ͷΛςετՄೳʹ͢Δ w ςετͷͱܾఆੑΛ্ͤ͞Δ w ҙ
w ςετ͕੬͘ͳΓɺมߋΛ͛Δʢརͷཪฦ͠ʣ w ςετͷِӄੑΛট͘ʢࣗ࡞ࣗԋςετʣ
"HFOEB࿈ࡌ֤ճͷςʔϚ ֶश༻ςετ ِཅੑͱِӄੑ ςεταΠζ ςετμϒϧ ςετϐϥϛου 🦁
ࣗಈςετͷ৴པੑΛ தظతʹอͭ ࠷దͳόϥϯε
Ϣχοτ ΠϯςάϨʔγϣϯ && ίετ ࣮ੑ ςετέʔε ߴ
ߴ ܾఆੑ ςετϐϥϛου
ςετϐϥϛουͱΞΠεΫϦʔϜίʔϯΞϯνύλʔϯ IUUQTXBUJSNFMPOCMPHJOUSPEVDJOHUIFTPGUXBSFUFTUJOHJDFDSFBNDPOF
ࠞཚղऍͷϒϨ͔Βੜ͕ͪ͡
͜Ε·ͰͷݟΛ·ͱΊΔͱ ֶश༻ςετ ِཅੑͱِӄੑ ςεταΠζ ςετμϒϧ ςετϐϥϛου 🦁 🦁 🦁 🦁
4NBMM .FEJVN -BSHF ίετ ࣮ੑ ςετέʔε ߴ
ߴ ܾఆੑ ·ͱΊςετμϒϧͰαΠζμϯͯ͠ɺ֤αΠζΛϐϥϛουܕʹஔ͠ɺςετશମͷ৴པੑΛҡ࣋͢Δ ςετμϒϧ ςετμϒϧ ςετ༰қੑઃܭ υϝΠϯઃܭ
͓ΘΓʹ
ࣦ৬ͷةػྑॻ͗͢Δ IUUQTCPPLNZOBWJKQFDQSPEVDUTEFUBJMJE
ࣦ৬ͷةػ͍͔ʹࢲͷݴ͍ͦ͏ͳ͜ͱΛݴ͏"* IUUQTUXJUUFSDPNLBXBTJNBTUBUVT
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ 📷🙆 🙆 'PSLXFMMจԽࡇ@"