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.6k
Spockで学ぶテスト駆動開発のコツ
yonetty
1
1.3k
Testing Java With Spock
yonetty
0
120
Other Decks in Programming
See All in Programming
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
420
dotNET_vulnclicker_intro.pdf
deka_morita
0
150
設計次第でAIコードの読む量は減らせる / designing-for-code-reading
minodriven
35
17k
作れる、でも消せるか?──安全に「枯らして消す」機能削除術 / Drain, Then Delete
chobishiba
2
1k
Kotlinの15年とServer-Side Kotlin
n_takehata
1
170
全ての永続トークンを、生まれる前に消し去りたい!
sylph01
2
1.3k
golang-bob.pdf
iwatsukayura
0
140
コードで差別化できない時代の ソフトウェアエンジニアリング / Software Engineering in an Era Where Code Doesn’t Differentiate
kishida
2
200
個人開発者よ、Honoを使え(おじさんver)
tanahiro2010
2
280
作って学ぶSpring BootのAuto Configuration / JJUG Night Seminar 2026-10-19
rshindo
0
210
エージェントを使い続けるためのメタワーク / Meta-work for keeping using the agent
rkaga
6
1.9k
気持ちぃ〜角丸 Squircle
ryu1013
0
340
Featured
See All Featured
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
790
How to Think Like a Performance Engineer
csswizardry
28
2.9k
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.5k
Highjacked: Video Game Concept Design
rkendrick25
PRO
1
490
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.3k
Leo the Paperboy
mayatellez
10
2.4k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
254
22k
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
540
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
440
Producing Creativity
orderedlist
PRO
348
41k
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
1
640
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
35k
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ஶΦϥΠϦʔɾδϟύϯץ ࢀߟจݙ