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
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.3k
Spockで学ぶテスト駆動開発のコツ
yonetty
1
1.3k
Testing Java With Spock
yonetty
0
110
Other Decks in Programming
See All in Programming
AI 輔助遺留系統現代化的經驗分享
jame2408
1
760
Vite+ Unified Toolchain for the Web
naokihaba
0
320
AIだと陥りがちなJakarta EE最新技術への移行時の落とし穴と解決策
tnagao7
0
110
dRuby over BLE
makicamel
2
380
並列実装の現場、2ヶ月間実務でAIを使い倒したAIもPCも私も限界が近い
ming_ayami
0
130
Mujeres en SEO Summit 2026 - Greatest Disaster Hits en Web Performance
guaca
0
190
A2UI という光を覗いてみる
satohjohn
1
140
Strategic Design in the Frontend: Moduliths & Micro Frontends @DDDEurope
manfredsteyer
PRO
0
110
技術記事、 専門家としてのプログラマ、 言語化
mizchi
13
6.2k
「AIで開発し、AIを届ける」をEvalでつなぐ 〜AIネイティブに始めるプロダクト開発の実践〜 / Connecting "Develop with AI, deliver AI" with Eval
rkaga
4
5.3k
Snowflake Summitでの新機能 CoCo / CoWork / snowflake-summit-2026-overall-what-new-coco
tatsuhiro
1
150
Signal Forms: Details & Live Coding @enterJS 2026 in Mannheim
manfredsteyer
PRO
0
160
Featured
See All Featured
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
360
30k
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
420
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
460
GraphQLとの向き合い方2022年版
quramy
50
15k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
250
Optimising Largest Contentful Paint
csswizardry
37
3.7k
Crafting Experiences
bethany
1
180
Building an army of robots
kneath
306
46k
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.2k
Being A Developer After 40
akosma
91
590k
Making the Leap to Tech Lead
cromwellryan
135
9.9k
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ஶΦϥΠϦʔɾδϟύϯץ ࢀߟจݙ