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
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
yonetty
February 16, 2021
Programming
470
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.4k
Spockで学ぶテスト駆動開発のコツ
yonetty
1
1.3k
Testing Java With Spock
yonetty
0
110
Other Decks in Programming
See All in Programming
Webフレームワークの ベンチマークについて
yusukebe
0
200
Mujeres en SEO Summit 2026 - Greatest Disaster Hits en Web Performance
guaca
0
240
Vite+ Unified Toolchain for the Web
naokihaba
0
740
えっ!!コードを読まずに開発を!?
hananouchi
0
190
AIを活用したE2Eテスト実装効率化のあゆみ / ebisu-mobile-14-kotetu
kotetuco
0
170
【やさしく解説 設計編 #1】「ドメイン駆動」と「実装駆動」ってなに? 〜設計の考え方を、たとえ話で学ぼう〜
panda728
PRO
1
110
共通化で考えるべきは、実装より公開する型だった
codeegg
0
210
気圧・高度・GPSを記録&可視化するアプリ「Koudo」を作った話
hjmkth
1
350
なぜ型を書くのか? TSKaigi2026で改めて考える #tskaigi_smarthr
kajitack
0
340
Vue × Nuxt × Oxc どこまで使える?実運用の現在地
andpad
0
370
ローカルLLMでどこまでコードが書けるか -縮小版 / How much code can be written on a local LLM Shortened
kishida
2
190
【やさしく解説 設計編・中級 #6】良いアーキテクチャとは ~ 一本の登り道の、行き先 ~
panda728
PRO
0
140
Featured
See All Featured
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
220
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.6k
A designer walks into a library…
pauljervisheath
211
24k
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
Abbi's Birthday
coloredviolet
3
8.6k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
56k
The Cult of Friendly URLs
andyhume
79
6.9k
AI Search: Where Are We & What Can We Do About It?
aleyda
0
7.7k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
A Soul's Torment
seathinner
6
3.1k
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
1
3.7k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
180
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ஶΦϥΠϦʔɾδϟύϯץ ࢀߟจݙ