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
『アジャイルソフトウェア開発の奥義』から学ぶテスト駆動開発
Search
yonetty
February 16, 2021
Programming
490
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
『アジャイルソフトウェア開発の奥義』から学ぶテスト駆動開発
社内の勉強会で使用した資料。
yonetty
February 16, 2021
More Decks by yonetty
See All by yonetty
技術書を読む技術(JJUG CCC 2023 Fall)
yonetty
5
1.5k
Spockで学ぶテスト駆動開発のコツ
yonetty
1
1.3k
Testing Java With Spock
yonetty
0
120
Other Decks in Programming
See All in Programming
Vue Fes Japan 2026 タイムテーブル徹底解説
448jp
0
160
モジュールの視点からSwiftを読み解く #iosdc
s_shimotori
0
170
自分的「カンファレンスの楽しみ方」
syumai
0
200
SREの越境 / SRE Collaboration
y0hgi
0
130
Kiroで創り、AgentCoreで繋ぐ!AWSで実践する「AI-DLC」から「AIエージェント統合」までの最新地図
licux
4
680
20260914 AIエージェント時代のPlatform Engineering LLM基盤とプロダクトの責務境界線
kanfab1
6
1.9k
iOSDC2026登壇資料.pdf
riofujimon
0
160
How I Stole PSI from Android Studio - DroidKaigi2026
worker8
0
130
App Intentsのビルドプロセスを支える技術
kntkymt
0
370
thread_parallel_with_free-threaded_Python_and_NumPy.pdf
riku_sakamoto
0
330
Claude Codeを組織的に動かして月400PRを実現した話
happy_ryo
0
280
App Storeの外へ──日本のiOSサイドローディング入門 for iOSDC Japan 2026
yuukiw00w
0
210
Featured
See All Featured
Side Projects
sachag
456
43k
The Curious Case for Waylosing
cassininazir
1
510
Paper Plane (Part 1)
katiecoart
PRO
2
11k
Crafting Experiences
bethany
1
340
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
240
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
840
Done Done
chrislema
186
16k
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
240
It's Worth the Effort
3n
188
29k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
57k
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.6k
Facilitating Awesome Meetings
lara
57
7.1k
Transcript
ʰΞδϟΠϧιϑτΣΞ։ൃͷ Ԟٛʱ͔ΒֶͿςετۦಈ։ൃ +BOVBSZUI 5BLFTIJ:POFLVCP !UZPOFLVCP
ςετϑΝʔετ ͱ ςετۦಈ։ൃ
ςετϑΝʔετ ϓϩμΫτίʔυΑΓઌʹ ςετίʔυΛॻ͘͜ͱ
ςετۦಈ։ൃ 5FTU%SJWFO%FWFMPQNFOU ςετίʔυΛಓ۩ʹ ͯ͠ɺ։ൃΛճ͢͜ͱ
ϨουάϦʔϯϦϑΝΫλϦϯά ᶃࣦഊ͢ΔςετΛॻ͘ ᶄςετ͕௨Δγϯϓϧ ͳίʔυΛॻ͘ ᶅϦϑΝΫλϦϯά͠ ͯίʔυΛ៉ྷʹ͢Δ
ςετϑΝʔετ͕ͩ ςετۦಈ։ൃͰͳ͍ྫ ઌʹͯ͢ͷςετίʔυΛॻ͘ class FooTest { def testFoo1() {
} def testFoo2() { } def testFoo3() { } def testFoo4() { } … } class Foo { // ͜Ε͔Β࣮ }
ςετϑΝʔετ͕ͩ ςετۦಈ։ൃͰͳ͍ྫ ᶃࣦഊ͢ΔςετΛॻ͘ ᶄςετ͕௨Δγϯϓϧ ͳίʔυΛॻ͘ ᶅϦϑΝΫλϦϯά͠ ͯίʔυΛ៉ྷʹ͢Δ ϑΟʔυόοΫͷܽ
ςετϑΝʔετ͕ͩ ςετۦಈ։ൃͰͳ͍ྫ ࣄલʹઃܭ͠ա͗Δ class FooTest { def testDoFoo() {
} } class BarTest { def testDoBar() { } }
ςετϑΝʔετ͕ͩ ςετۦಈ։ൃͰͳ͍ྫ ᶃࣦഊ͢ΔςετΛॻ͘ ᶄςετ͕௨Δγϯϓϧ ͳίʔυΛॻ͘ ᶅϦϑΝΫλϦϯά͠ ͯίʔυΛ៉ྷʹ͢Δ ϧʔϓճΔ͕ޮՌ͕ݮΔ
#%6' ࣄલͷઃܭΛΓա͗Δͱ ޡͬͨઃܭաઃܭΛੜΉ #JH%FTJHO6Q'SPOU
αϯΫίετ ઌʹίετΛͬͯߦͬͨઃܭ ࣺͯͮΒ͍ʢଛΓͰ͖ͳ͍ʣ 4VOL$PTU
2 5%%Ͱࣄલઃܭ͠ͳ͍ͷʁ
" ඞཁͳΒɺखॻ͖ͷϥϑεέον $3$ͳͲखܰʹ࡞Ͱ͖ࣺͯͯ ͍͢πʔϧΛ͏
ʮͳΜͱͳ͘ཧղͰ͖͚ͨͲ ۩ମతʹͲ͏ͬͯ5%%Λ ਐΊ͍͍͔ͯΘ͔Βͳ͍ʯ
ͱͯྑ͍ྫ͕͋Γ·ͨ͠ʂ
ʲୈষʳ ϓϩάϥϛϯά Τϐιʔυ
ϘϦϯάͷείΞूܭ ΞϓϦέʔγϣϯΛ5%% Ͱ։ൃ͢Δαϯϓϧ 4 5 1 5 14 4 29
6 6 133 2 49 5 60 1 61 0 77 7 97 6 117
w ٿॱʹͨ͠ϐϯΛه͢Δ w ࢦఆͨ͠ϑϨʔϜʹ͓͚ΔείΞΛܭࢉ Ͱ͖Δ w ࠷৽ͷείΞΛܭࢉͰ͖Δʢશͯͷٿ ͕͍ྃͯ͠Εɺ࠷ऴతͳείΞʣ 4 5
1 5 14 4 29 6 6 133 2 49 5 60 1 61 0 77 7 97 6 117 ৼΔ͍ʢΞϓϦέʔγϣϯ༷ʣ
ࣄલઃܭʢϥϑεέονʣ
Ϙϒ͓͡͞Μͱಉ྅͕ ϖΞϓϩͰḷͬͨಓے
w ςετ͖͢5ISPXͷৼ͍͕ݟ͍ͩͤͣɺ 'SBNFͷςετ͔Βॻ͖࢝Ίͨɻ w ࠷୯७ͳςετέʔε͔Β࢝Ίɺ࠷୯७ͳ ࣮ͰςετΛ௨͢ɻ ࠷ॳͷςετέʔε public class Frame
{ public int getScore() { return 0 ; } } class FrameSpec extends Specification { def "ະٿͷͱ͖ͷείΞ0Ͱ͋Δ"() { given : def f = new Frame( ) when : def score = f.getScore( ) then : score == 0 } } ˞ॻ੶Ͱ+6OJUΛ͍ͬͯΔ ͕ɺຊࢿྉͰ4QPDLΛ༻
w ࣍ʹ୯७ͳςετέʔεΛՃ͠ɺςετ͕௨ ΔΑ͏ʹίʔυΛमਖ਼͢Δ ࣍ͷςετέʔε class FrameSpec extends Specification { ..
def "1ճٿͨ͠ͱ͖ʹείΞ͕ਖ਼͍͠"() { given : def f = new Frame( ) when : f.add(5 ) then : f.getScore() == 5 } } public class Frame { private int itsScore = 0 ; public int getScore() { return itsScore ; } public void add(int pins) { itsScore += pins ; } }
ग़ͩ͠ॱௐʂ
w εϖΞετϥΠΫΛग़ͨ͠߹ɺϑϨʔϜͷ είΞܭࢉʹޙଓͷϑϨʔϜͷใ͕ඞཁɻ w (BNFΦϒδΣΫτ'SBNFΛϦϯΫϦετͰ ཧ͖͢ʁ w 'SBNFͷ࡞ۀΛதஅͯ͠ɺ(BNFͷ࡞ۀʹΓ ସ͑Δɻ ෳճٿͨ͠߹ʁ
(BNFͷ࣮Λগͣͭ͠ਐΊΔ class GameSpec extends Specification { when : g.add(5 )
g.add(4 ) g.add(7 ) g.add(2 ) then : g.score() == 1 8 g.scoreForFrame(1) == 9 g.scoreForFrame(2) == 1 8 } public class Game { private int itsScore = 0 ; private int[] itsThrows = new int[21] ; private int itsCurrentThrow = 0 ; public int score() { return itsScore ; } public void add(int pins) { itsThrows[itsCurrentThrow++] = pins ; itsScore += pins ; } public int scoreForFrame(int frame) { int score = 0 ; for (int ball = 0; frame > 0 && (ball < itsCurrentThrow) ; ball += 2, frame--) { score += itsThrows[ball] + itsThrows[ball + 1] ; } return score ; } }
lίʔυ͕ͦΕΛඞཁͩͱ ओு͠ͳ͍ݶΓɺϦϯΫϦετ ༻ҙͨ͘͠ͳ͍Μͩz
w ୯ͳΔྻͰ༻Λ͢ͳΒɺͦΕͰ0, w ઃܭ্ͷஅΛΒͤΔ γϯϓϧͳઃܭΛબ͠Α͏ public class Game { private
int itsScore = 0 ; private int[] itsThrows = new int[21] ; private int itsCurrentThrow = 0 ;
w ςετ͕͋Δ͔Β҆৺ϦϑΝΫλϦϯά ৗʹϦϑΝΫλϦϯά͠Α͏ public int scoreForFrame(int frame) { int score
= 0 ; for (int ball = 0; frame > 0 && (ball < itsCurrentThrow) ; ball += 2, frame--) { score += itsThrows[ball] + itsThrows[ball + 1] ; } return score ; } public int scoreForFrame(int theFrame) { int ball = 0 ; int score = 0 ; for (int currentFrame = 0; currentFrame < theFrame ; currentFrame++) { int firstThrow = itsThrows[ball++] ; int secondThrow = itsThrows[ball++] ; score += firstThrow + secondThrow ; } return score ; }
w εϖΞΛग़ͨ͠ͱ͖ w ετϥΠΫΛग़ͨ͠ͱ͖ w ύʔϑΣΫτήʔϜ w ϦΞϧͳαϯϓϧ w ΤοδέʔεʢύʔϑΣΫτήʔϜະͳͲʣ
ਐతʹ(BNFͷ࣮ΛਐΊΔ 4 5 1 5 14 4 29 6 6 133 2 49 5 60 1 61 0 77 7 97 6 117
w શͯͷςετέʔε͕௨ΓɺΞϓϦέʔγϣϯ ͷৼΔ͍͕͕ͨ͠ɺϦϑΝΫλϦϯά ଓ͍͍ͯ͘ɻ w 4DPSFSΦϒδΣΫτͷඞཁੑΛΘͤͳ͕ Βɺͪ͝Ό͍ͭͨίʔυΛ͖Ε͍ʹ͍ͯ͘͠ɻ ͞ΒͳΔϦϑΝΫλϦϯά
if (strike()) { score += 10 + nextTwoBallsForStrike() ; ball++
; } else if (spare()) { score += 10 + nextBallForSpare() ; ball+=2 ; } else { score += handleSecondThrow() ; } l͜ͷTDPSF'PS'SBNFؔΛݟͯ͝ΒΜΑʂ ͜Εͦ͜ϘϦϯάͷϧʔϧΛ͖ΘΊͯ؆ܿ ʹهड़ͨ࢟ͩ͠Αʂz
ܗ l͜ΕͰɺ(BNFϑϨʔϜͷཧ͚ͩΛͯ͠ɺ 4DPSFSείΞͷܭࢉ͚ͩΛ୲͢Δਤࣜʹͳͬ ͨͶɻ͜Εͧɺ୯Ұͷݪଇʢ431ʣͩʂz
ͲͪΒͷઃܭ͕͙͢Ε͍ͯΔ͔ʁ if (strike()) { score += 10 + nextTwoBallsForStrike() ;
ball++ ; } else if (spare()) { score += 10 + nextBallForSpare() ; ball+=2 ; } else { score += handleSecondThrow() ; } ࣄલͷઃܭ 5%%ʹΑΔઃܭ
దͳϞσϦϯά ࣮ੈքͷ֓೦ߏΛ࣮ʹղܾྖ Ҭʹ࠶ݱ͢Δ͜ͱ͕͍ͭਖ਼͍͠ ͱݶΒͳ͍
ٙ 4DPSFSςετ͠ͳ͍ͷʁ
ϢχοτςετͷʮϢχοτʯ lϢχοτͱ;Δ·͍ͷ୯ Ґɺͭ·Γಠཱͨ͠ݕূՄ ೳͳ;Δ·͍ͷ͜ͱͩz
ৼ͍ͷू߹ମΛςετ͢Δ l͋ΒΏΔ؍Մೳͳ;Δ· ͍͕ɺͦΕʹඥͮ͘ςετ Λ͖࣋ͭͰ͋Δ͜ͱΛҙ ຯ͢Δɻz
ৼΔ͍ͷू߹ମͷϑΝαʔυͰ ͋Δ(BNFΛςετ͢Ε0,
࣮ࡍɺΧόϨοδͳ͔ͬͨ
w 5%%ͷαΠΫϧͰ(BNFͷৼ͍Λશ࣮ͯ͠ ͨޙɺϦϑΝΫλϦϯάͰ4DPSFSΛநग़ɻ w (BNF4QFDͰৼ͍Λݻఆ͢Δ͜ͱͰɺϦ ϑΝΫλϦϯάΛߦ͏͜ͱ͕Ͱ͖ͨɻ Ϙϒ͓͡͞Μୡ͕ḷͬͨ࿏
w ॻ੶ͷதͰϘϒ͓͡͞Μୡ͕ḷͬͨ࿏ΛɺԾʹ ηΠόʔϧʔτͱݺͿʢ࣭ड͚͚ͳ͍ʣ 5%%ͷϧʔτҰͭͱݶΒͳ͍
w 4DPSFSͷඞཁੑ͕ݟ͑ͨஈ֊Ͱ4DPSFS4QFD Λ࡞͠ɺ5%%Ͱ4DPSFSΛઌʹ্͛Δɻ w ΠϯαΠυΞτʢϘτϜΞοϓʣɻ ႒ϧʔτ
w 4DPSFSͷඞཁੑ͕ݟ͑ͨΒɺ4DPSFSͷϞοΫ Λͬͯ(BNFͷ࣮ΛਐΊ͍ͯ͘ɻ w ΞταΠυΠϯʢτοϓμϯʣɻ ࡩϧʔτ
ϞοΫΛͬͨςετ private Game g private Scorer s def setup() {
s = Mock() // ScorerͷϞοΫ g = new Game(s ) } def "2ճٿͨ͠ͱ͖ͷείΞ͕ਖ਼͍͠"() { when : g.add(5 ) g.add(4 ) def score = g.score( ) then : score == 9 1 * s.addThrow(5 ) 1 * s.addThrow(4 ) 1 * s.scoreForFrame(2) >> 9 } ؒೖྗ ؒग़ྗ ʨ ૬ޓ࡞༻ͷݕূ
w (BNFΛपΓ͔Βಠཱͯ͠ςετͰ͖Δɻ w 4DPSFSͷ࣮͕ͳ͍࣌Ͱɺઌʹ(BNFΛςε τͰ͖Δɻ w ϞοΫΛܦ༝͠ɺؒೖྗؒग़ྗΛͬͯ (BNFͷৼ͍ঢ়ଶΛνΣοΫͰ͖Δɻ w (BNFͱ4DPSFSͷ૬ޓ࡞༻ΛδϟετΠϯλΠ
ϜͰઃܭͰ͖Δɻ ϞοΫΞϓϩʔνͷϝϦοτ
w ࣮ͷৄࡉʹґଘ͢ΔͨΊɺ੬͍ςετͱͳΓ ͍͢ɻ w ॻ͘ͷʹख͕͔͔ؒΔɻ w (BNF 4DPSFSʢৼ͍ͷू߹ମʣʹର͢Δ ςετผ్ॻ͘ඞཁ͕͋Δɻ ϞοΫΞϓϩʔνͷσϝϦοτ
w ϞοΫΛͬͯॻ͍ͨ(BNF4QFD͋͘·Ͱ ઃܭΛਐΊΔҰ࣌తͳಓ۩ͱߟ͑ɺࣺͯͯΑ͠ ʢৼ͍ͷू߹ମʹର͢Δςετ͕ΕՄʣ ઃܭͷͨΊ͚ͩͷςετίʔυ
·ͱΊ
5%%ͷຊ࣭ɺ ϨουάϦʔϯϦϑΝΫλϦϯά ͷαΠΫϧͰߦ͏ δϟετΠϯλΠϜͷઃܭͰ͋Δ
Ϣχοτςετͷ୯Ґ ৼ͍ͷू߹ମͱ͠Α͏
ʰΞδϟΠϧιϑτΣΞ։ൃͷ ԞٛʱষΛࣸܦͯ͠Έ·͠ΐ͏
ʰΞδϟΠϧιϑτΣΞ։ൃͷԞٛୈ̎൛ʱ ϩόʔτɾ$ɾϚʔνϯஶ4#ΫϦΤΠςΟϒץ ʰϨΨγʔίʔυ͔Βͷ٫ʱ %BWJE4DPUU#FSOTUFJOஶΦϥΠϦʔɾδϟύϯץ ࢀߟจݙ