Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PHPバージョンアップと決済リプレイスを支えたユニットテスト #phpcon

PHPバージョンアップと決済リプレイスを支えたユニットテスト #phpcon

PHP Conference 2018での登壇資料です。

- なぜ我々はユニットテストが必要なのか
- 既存コードを保護する技法
- ユニットテスト量を増やす試み
- ユニットテスト増加における課題と対策
- テストがないコードを再生産しない技法
- まとめ

88964b936e864ca7d326272eaa70fa9a?s=128

Kazuki Higashiguchi

December 13, 2018
Tweet

Transcript

  1. PHPόʔδϣϯΞοϓͱ ܾࡁϦϓϨΠεΛࢧ͑ͨ Ϣχοτςετ 2018/12/15 (Sat) PHP Conference 2018 Kazuki Higashiguchi

    / BASE, Inc.
  2. Theme of this Talk • ςετ͕গͳ͍ίʔυϕʔεʹରͯ͠Ϣχο τςετΛॻ͍͍ͯͨ͘Ίͷٕ๏ • ςετ͕ແ͍ίʔυΛ࡞Βͳ͍ͨΊͷΞϓ ϩʔν

  3. About me • ౦ޱ ࿨ᏻ (@higasgt) • Server Side EngineerʢPHP

    / Goʣ • BASE, Inc. / BASE Product Division • PHPόʔδϣϯΞοϓ / ޙ෷͍ܾࡁϦϓϨΠε / YELL BANK • Blog: http://khigashigashi.hatenablog.com/
  4. About BASE Ձ஋ͷަ׵ΛΑΓγϯϓϧʹ͠ɺ ੈքதͷਓʑ͕࠷దͳܦࡁ׆ಈΛߦ͑ΔΑ͏ʹ͢Δɻ MISSION ωοτγϣοϓ࡞੒αʔϏε ʮBASEʯ γϣοϐϯάΞϓϦ ʮBASEʯ

  5. Agenda 1. ͳͥզʑ͸Ϣχοτςετ͕ඞཁͳͷ͔ 2. طଘίʔυΛอޢ͢Δٕ๏ 3. ϢχοτςετྔΛ૿΍͢ࢼΈ 4. Ϣχοτςετ૿Ճʹ͓͚Δ՝୊ͱରࡦ 5.

    ςετ͕ͳ͍ίʔυΛ࠶ੜ࢈͠ͳ͍ٕ๏ 6. ·ͱΊ
  6. 1. ͳͥզʑ͸Ϣχοτςετ ͕ඞཁͳͷ͔

  7. BASE 2017೥ͷ֓گ • 2012೥αʔϏε։࢝ • ଟ͘ͷαʔϏεͰPHP5.3/CakePHP2.3Λ ར༻ • Ϣχοτςετ͕ॻ͔Ε͍ͯΔαʔϏε͕ গͳ͔ͬͨ

  8. Ϣχοτςετ͕গͳ͍͕ނʹ  • ʮϨΨγʔίʔυʯͱͳΔίʔυϕʔε • อक·ͨ͸֦ு͕ࠔ೉ʹͳΓ͏Δ

  9. –ϚΠέϧɾCɾϑΣβʔζஶ ʰϨΨγʔίʔυվળΨΠυʱ “ϨΨγʔίʔυͱ͸ɺ ୯ʹςετͷͳ͍ίʔυͰ͢ɻ” IUUQTXXXTIPFJTIBDPKQCPPLEFUBJM

  10. • ີ݁߹ͳίʔυઃܭ • ϢχοτςετΛॻ͍͍ͯͳ͍ίʔυ͸ɺ ີ݁߹ʹͳΓςετ͕ॻ͖ͮΒ͍ίʔυ ʹͳ͍ͬͯΔέʔε͕ଟ͍  Ϣχοτςετ͕গͳ͍͕ނʹ

  11. “ίʔυΛมߋ͢ΔͨΊʹ͸ɺςετΛ੔ උ͢Δඞཁ͕͋Δɻଟ͘ͷ৔߹͸ɺςε τΛ੔උ͢ΔͨΊʹ͸ɺίʔυΛมߋ͢ Δඞཁ͕͋Δɻ” ʢϨΨγʔίʔυͷδϨϯϚʣ –ʰϨΨγʔίʔυվળΨΠυʱ

  12. • ೔ʑɺอकɾ֦ுΛ͍ͯ͘͠αʔϏεͷίʔ υϕʔε • อकɾ֦ுʹ͋ͨΓɺਖ਼͘͠ಈ͘͜ͱ͕ٻ ΊΒΕΔ • →ʮϨΨγʔίʔυʯͷࠀ෰ʹର͢ΔϞν ϕʔγϣϯ 

    ՝୊ײ
  13. อकɾ֦ுʹର͢Δཁٻ  1. طଘͷৼΔ෣͍Λม͑ͳ͍͜ͱ 2. طଘͷৼΔ෣͍Λมߋͯ͠ਖ਼͘͠ಈ͘͜ ͱ 3. ৽نͷৼΔ෣͍Λ௥Ճͯ͠ਖ਼͘͠ಈ͘͜ ͱ

    େ͖͘3छྨͷཁٻͱͱ΋ʹ೔ʑͷ։ൃΛ͠ ͍ͯΔɻ
  14. - อकɾ֦ுʹର͢Δཁٻɿࣄྫ - 1. طଘͷৼΔ෣͍Λม͑ͳ͍ • ʮPHPɾCakePHPόʔδϣϯΞοϓʯ • 2016೥͔Β࢝·ͬͨPHPɾCakePHPͷ όʔδϣϯΞοϓσʔτ

    • PHP5.3 -> PHP7.1 • CakePHP2.3~2.10 -> CakePHP2.10(2.x ࠷৽) • 2018೥5݄ʹ׬ྃ
  15. • 60ສళฮͷγϣοϓ͕ར༻͍ͯ͠ΔαʔϏ εͷݴޠɾϑϨʔϜϫʔΫͷόʔδϣϯΞο ϓ • ίʔυϕʔεશମʹର͢ΔӨڹൣғ • PHPɾCakePHPͷόʔδϣϯΛ҆શʹ্͛ Δඞཁੑ 

    - อकɾ֦ுʹର͢Δཁٻɿ1. طଘͷৼΔ෣͍Λม͑ͳ͍ - PHP/CakePHPόʔδϣϯΞοϓ
  16. • ςετΧόϨοδΛ্͛ͯɺอޢൣғΛ޿ ͛Δ • ControllerϨϕϧ͔Β޿ൣғͷΧόϨοδ Λर͍ͬͯ͘  - PHP/CakePHPόʔδϣϯΞοϓ -

    ςετʹΑ࣮ͬͯݱ͍ͨ͜͠ͱ
  17. • ʮޙ෷͍ܾࡁϦϓϨΠεʯ • BASE͸ओʹҎԼ5ͭͷܾࡁํ๏ΛରԠ • ΫϨδοτΧʔυܾࡁɺίϯϏχܾࡁɾPay-easyɺۜ ߦৼࠐɺޙ෷͍ܾࡁɺΩϟϦΞܾࡁ • ʮޙ෷͍ܾࡁʯͷϦϓϨΠεΛ࣮ࢪɻ IUUQTCBTFVKQ

    - อकɾ֦ுʹର͢Δཁٻɿࣄྫ - 2. طଘͷৼΔ෣͍Λมߋ͢Δ
  18. • Ϣʔβʔͷ͓͕ۚؔΘΔͷͰɺԿࣄ΋ͳ͘ ҆શʹ׬਱͢Δඞཁੑ • طଘίʔυͷৼΔ෣͍Λཧղ্ͨ͢͠Ͱख ΛೖΕΔ͜ͱ͕ٻΊΒΕΔɻ • طଘͷৼΔ෣͍Λอޢ্ͨ͠ͰɺϦϑΝΫ λϦϯάɾৼΔ෣͍௥ՃΛߦ͍͍ͨɻ 

    - ޙ෷͍ܾࡁϦϓϨΠε - ςετʹΑ࣮ͬͯݱ͍ͨ͜͠ͱ
  19. • ʮYELL BANKʢΤʔϧόϯΫʣʯ • γϣοϓͷ௅ઓΛԠԉ͢ΔࢿۚௐୡαʔϏ ε IUUQTUIFCBTFJOZFMMCBOL - อकɾ֦ுʹର͢Δཁٻɿࣄྫ -

    3. ৽نͷৼΔ෣͍Λ௥Ճ͢Δ
  20. • ओͱͳΔػೳ͸Web APIͰ࣮૷ɺBASEຊ ମͷίʔυϕʔε͔ΒΞΫηε • ʮϨΨγʔίʔυʯͱͳΒͳ͍อकੑͷ͋ ΔίʔυΛॻ͖͍ͨɻ • ૄ݁߹ͳίʔυઃܭΛਪਐ͠ɺৼΔ෣͍อ ޢΛଅਐ͢Δ

     - อकɾ֦ுʹର͢Δཁٻɿ৽نͷৼΔ෣͍Λ௥Ճ͢Δ - YELL BANKʢΤʔϧόϯΫʣ
  21. ڞ௨తͳϞνϕʔγϣϯ • ςετΛॻ͘͜ͱʹΑͬͯɺΑΓ҆શʹγ εςϜΛѻ͍͍ͨϞνϕʔγϣϯ • ฤूͯ͠فΔʢEdit and Prayʣ • อޢͯ͠มߋ͢ΔʢCover

    and Modifyʣ • ૄ݁߹ͳίʔυઃܭʹ͠ɺ৽نʹϨΨγʔ ίʔυΛ࢈·ͳ͍
  22. • ҆શʹαʔϏεΛอकɾ੒௕͢ΔͨΊʹɺ طଘͷৼΔ෣͍Λอূ͍ͨ͠ɻ • ৽نʹॻ͘ίʔυʹ͸อकੑΛ΋ͨͤͨ ͍ɻ • ϢχοτςετΛॻ͍͍ͯ͘ɻ  1.

    ·ͱΊ
  23. 2. طଘίʔυΛอޢ͢Δٕ๏

  24. طଘίʔυΛอޢ͢Δٕ๏ • ҆શʹطଘίʔυΛѻ͍͍ͨ • ͢Ͱʹଘࡏ͢Δίʔυʹରͯ͠ৼΔ෣͍Λ อޢ͢Δ • ͦͷ্ͰɺϦϑΝΫλϦϯά͍ͯͨ͘͠Ί ͷɺϢχοτςετͷ࢖͍ํ

  25. Ϣχοτςετᴈ໌ظͷϚΠϯυ • طଘίʔυʹςετ͕ͳ͍ͨΊɺϊ΢ϋ΢ ΋গͳ͍ • ʮͲ͜·Ͱςετ͢Δ͔ʯͱ͍͏໎͍͕ͭ ͖·ͱ͏ • →࠷ॳ͸ɺগ͠ա৒͔΋ͱࢥ͏͘Β͍Ͱॻ ͍͍ͯ͘

    • ʮͱʹ͔͘ॻ͘ʯ͜ͱʹॏ఺
  26. طଘίʔυΛอޢ͢Δٕ๏ طଘίʔυΛอޢ͢Δ2ͭͷٕ๏ 1. ࢓༷Խςετ / ௐࠪతϦϑΝΫλϦϯά 2. ϨΨγʔίʔυͷδϨϯϚͱͷ֨ಆ

  27. - طଘίʔυΛอޢ͢Δٕ๏ - 1. ࢓༷Խςετ • “characterization test” • ίʔυͷطଘͷৼΔ෣͍Λ໌Β͔ʹ͢Δς

    ετ • ॲཧ಺Ͱૢ࡞͢Δཁૉʹର͢Δ࣮ࢪ͍ͯ͠ ͘ • Viewʹηοτ͞ΕΔ஋ • Sessionͷ஋ • Dataͷొ࿥/ߋ৽ • FUD 
  28. • “exploratory refactoring” • طଘίʔυʹର͢ΔཧղΛਂΊΔ • “ʮະ஌΁ͷڪΕʯΛࠀ෰͢Δ࠷ྑͷํ๏͸ɺͦͷ ίʔυʹඈͼࠐΜͰɺ͍͡Γ࢝ΊΔ͜ͱͩɻ” (ʰϨΨ γʔιϑτ΢ΣΞվળΨΠυʱ)

    • ཧղΛਂΊΔͨΊิॿͱͯ͠ʮ࢓༷Խςε τʯΛߦ͏  https://www.shoeisha.co.jp/book/detail/9784798145143 - طଘίʔυΛอޢ͢Δٕ๏ɿ1. ࢓༷Խςετ - ௐࠪతϦϑΝΫλϦϯά
  29. 1. ςετίʔυͷதͰର৅ͷίʔυΛݺͼ ग़͢ 2. ࣦഊ͢ΔͱΘ͔͍ͬͯΔද໌Λॻ͘ 3. ࣦഊͨ݁͠Ռ͔Β࣮ࡍͷৼΔ෣͍Λ֬ೝ ͢Δ 4. ίʔυ͕࣮ݱ͢ΔৼΔ෣͍Λظ଴͢ΔΑ

    ͏ʹɺςετΛมߋ͢Δ 5. Ҏ্ͷखॱΛ܁Γฦ͢  - طଘίʔυΛอޢ͢Δٕ๏ɿ1. ࢓༷Խςετ - ࢓༷Խςετͷखॱ
  30. - 1. ࢓༷Խςετɿ࢓༷Խςετͷखॱ - 1. ςετίʔυͷதͰର৅ͷίʔυΛ ݺͼग़͢ $result = $this->testAction(

    ‘/samples/index’, [‘data’ => $data, ‘method’ => ‘post’] ); 1. ςετίʔυͷதͰର৅ͷίʔυΛݺͼग़͢
  31. $result = $this->testAction( ‘/samples/index’, [‘data’ => $data, ‘method’ => ‘post’]

    ); $expected = []; $this->assertSame($expected, $this->vars); 2. ࣦഊ͢ΔͱΘ͔͍ͬͯΔද໌Λॻ͘ - 1. ࢓༷Խςετɿ࢓༷Խςετͷखॱ - 2. ࣦഊ͢ΔͱΘ͔͍ͬͯΔද໌Λॻ͘
  32. $ ./Console/cake test app —-stderr Controller/SampleController PHPUnit 5.7.27 by Sebastian

    Bergmann and contributors. F 1 / 1 (100%) Time: 19.32 seconds, Memory: 16.00MB There was 1 failure: --- Expected +++ Actual @@ @@ -Array &0 () +Array &0 ( ‘result’ => [‘success’] ) 3. ࣦഊͨ݁͠Ռ͔Β࣮ࡍͷৼΔ෣͍Λ֬ೝ͢Δ - 1. ࢓༷Խςετɿ࢓༷Խςετͷखॱ - 3. ࣦഊͨ݁͠Ռ͔Β࣮ࡍͷৼΔ෣͍Λ ֬ೝ͢Δ
  33. $result = $this->testAction( ‘/samples/index’, [‘data’ => $data, ‘method’ => ‘post’]

    ); $expected = [ ‘result’ => [‘success’] ]; $this->assertSame($expected, $this->vars); 4. ίʔυ͕࣮ݱ͢ΔৼΔ෣͍Λظ଴͢ΔΑ͏ ʹɺςετΛมߋ͢Δ 5. Ҏ্ͷखॱΛ܁Γฦ͢ - 1. ࢓༷Խςετɿ࢓༷Խςετͷखॱ - 4. ίʔυ͕࣮ݱ͢ΔৼΔ෣͍Λظ଴͢ ΔΑ͏ʹɺςετΛมߋ͢Δ
  34. • طଘίʔυͷৼΔ෣͍Λྫ֎ܥؚΊͯอূ ͢Δࣄ͕Մೳ • ςετΛॻ͘͜ͱͰݱࡏͷ࣮૷࢓༷Λཧղ ͢Δ͜ͱ͕Ͱ͖Δ • ҆શͳϦϑΝΫλϦϯάʹͭͳ͕Δ  -

    طଘίʔυΛอޢ͢Δٕ๏ɿ1. ࢓༷Խςετ - ࢓༷Խςετͷޮ༻
  35. 1. ࢓༷ԽςετΛॻ͘ 2. ςετ͕௨Δ͜ͱΛ֬ೝ͢Δ 3. ϦϑΝΫλϦϯά͢Δ 4. ςετ͕௨Δ͜ͱΛ֬ೝ͢Δ  -

    طଘίʔυΛอޢ͢Δٕ๏ɿ1. ࢓༷Խςετ - ҆શͳϦϑΝΫλϦϯάͷखॱ
  36. - ҆શͳϦϑΝΫλϦϯάɿྫ - ର৅ϝιου /** * ར༻Մೳ͔Ͳ͏͔Λ൑ఆ͢Δ * @param int|null

    $user_id * @return bool */ public function canUse(int $user_id = null): bool { if (!is_null($user_id)) { $user = $this->User->find('first', [ 'conditions' => ['user_id' => $user_id] ] ); if (empty($user)) { return false; } $available = $user['User']['available']; return $available; } else { return false; } } ૣظreturn͢ΔίʔυʹϦϑΝΫλϦϯά͍ͨ͠৔߹
  37. /** * @dataProvider dataProvider_canUse * @param int|null $user_id * @param

    bool $expected */ public function test_canUse(?int $user_id, bool $expected): void { $this->assertSame($expected, $this->User->canUse($user_id)); } public function dataProvider_canUse(): array { return [ 'user_id͕null' => [null, false], 'ଘࡏ͢Δuser_idͰར༻Մೳ' => [1, true], 'ଘࡏ͢Δuser_idͰར༻ෆՄ' => [2, false], ]; } ϦϑΝΫλϦϯάର৅ϝιουʹର͢ΔςετΛॻ͘ - ҆શͳϦϑΝΫλϦϯάɿྫ - 1. ࢓༷ԽςετΛॻ͘
  38. /** * @dataProvider dataProvider_canUse * @param int|null $user_id * @param

    bool $expected */ public function test_canUse(?int $user_id, bool $expected): void { $this->assertSame($expected, $this->User->canUse($user_id)); } public function dataProvider_canUse(): array { return [ 'user_id͕null' => [null, false], 'ଘࡏ͢Δuser_idͰར༻Մೳ' => [1, true], 'ଘࡏ͢Δuser_idͰར༻ෆՄ' => [2, false], ]; } PHPUnitͷdataProviderΛར༻͢Δ͜ͱͰςετέʔεΛγϯϓϧʹ - ҆શͳϦϑΝΫλϦϯάɿྫ - 1. ࢓༷ԽςετΛॻ͘
  39. -> % ./app/Console/cake test app User --filter test_canUse PHPUnit 5.7.27

    by Sebastian Bergmann and contributors. ... 3 / 3 (100%) Time: 5.9 seconds, Memory: 14.00MB OK (3 tests, 3 assertions) - ҆શͳϦϑΝΫλϦϯάɿྫ - 2. ςετ͕௨Δ͜ͱΛ֬ೝ͢Δ
  40. - ҆શͳϦϑΝΫλϦϯάɿྫ - 3. ϦϑΝΫλϦϯά͢Δ /** * ར༻Մೳ͔Ͳ͏͔Λ൑ఆ͢Δ * @param

    int|null $user_id * @return bool */ public function canUse(int $user_id = null): bool { if (is_null($user_id)) { return false; } $user = $this->User->find('first', [ 'conditions' => ['user_id' => $user_id] ] ); if (empty($user)) { return false; } $available = $user['User']['available']; return $available; } ૣظreturn͢ΔίʔυʹϦϑΝΫλϦϯά
  41. -> % ./app/Console/cake test app User --filter test_canUse PHPUnit 5.7.27

    by Sebastian Bergmann and contributors. ... 3 / 3 (100%) Time: 5.9 seconds, Memory: 14.00MB OK (3 tests, 3 assertions) - ҆શͳϦϑΝΫλϦϯάɿྫ - 4. ςετ͕௨Δ͜ͱΛ֬ೝ͢Δ
  42. • ςετΛॻͨ͘ΊʹɺίʔυΛมߋ͢Δඞ ཁ͕͋Δέʔε͕͋Δ • ͍ΘΏΔɺςετ͠ʹ͍͘ίʔυʹରࡦ͕ ඞཁ  - طଘίʔυΛอޢ͢Δٕ๏ -

    2. ϨΨγʔίʔυͷδϨϯϚͱͷ֨ಆ
  43. “ίʔυΛมߋ͢ΔͨΊʹ͸ɺςετΛ੔ උ͢Δඞཁ͕͋Δɻଟ͘ͷ৔߹͸ɺςε τΛ੔උ͢ΔͨΊʹ͸ɺίʔυΛมߋ͢ Δඞཁ͕͋Δɻ” ʢϨΨγʔίʔυͷδϨϯϚʣ –ʰϨΨγʔίʔυվળΨΠυʱ

  44. • ςετ͕ͳ͍ίʔυ͸ɺςετ͠ʹ͍͘ ίʔυͰ͋Δ͜ͱ͕ଟ͍ • ֎෦઀ଓΛؚΉ࣮૷ͱͷີ݁߹ • ܾࡁγεςϜɾAWS • ੹຿ͷେ͖͍ϝιου 

    - طଘίʔυΛอޢ͢Δٕ๏ɿ2. ϨΨγʔίʔυ - ςετ͠ʹ͍͘ίʔυ
  45. • ςετ͕͔͚ΔΑ͏ʹॻ͖׵͑Δ • ີ݁߹ΛMockΛࠩ͠ࠐΊΔஈ֊·Ͱղফ ͢Δ • ςετ࣌ʹMockΛࠩ͠ࠐΉ • ֎෦࿈ܞͷৼΔ෣͍ͷMockΫϥεΛ࡞੒ •

    ֎෦࿈ܞͳͲΛؚΉςετΛߦ͏ࡍɺ֘ ౰ΫϥεΛMockʹஔ͖׵͑Δ  - طଘίʔυΛอޢ͢Δٕ๏ɿ2. ϨΨγʔίʔυ - ςετ͠ʹ͍͘ίʔυ΁ͷରࡦ
  46. • σβΠϯύλʔϯͷҰͭ • ֎෦͔Βґଘؔ܎ͷ͋ΔΦϒδΣΫτΛ஫ ೖ͢Δ • ;Δ·͍ͱґଘੑղܾΛ෼཭ • https://github.com/google/guice/wiki/Motivation •

    Martin FowlerࢯʹΑΓఏএ͞Εͨ༻ޠ • https://www.martinfowler.com/articles/injection.html  - طଘίʔυΛอޢ͢Δٕ๏ɿ2. ϨΨγʔίʔυ - Dependency Injection
  47. େ͖͘3ͭͷDIͷ΍Γํ • Constructor Injection • Setter Injection • Interface Injection

     - Dependency Injection - DI Pattern IUUQTXXXNBSUJOGPXMFSDPNBSUJDMFTJOKFDUJPOIUNM
  48. • खಈDI͔ɺDI ContainerʹΑΔࣗಈDI͔ɺঢ় گʹԠͯ͡બ୒  - Dependency Injection - DIઓུ

  49. // Before public function charge($order) { $manager = new PaymentManager();

    $result = $manager->charge($order); // ܾࡁγεςϜʹ௨஌ } PaymentManagerͱີ݁߹ɺ Mock΁ͷࠩ͠ସ͕͑೉͍͠ - ςετ͠ʹ͍͘ίʔυɿྫ - खಈDIͰີ݁߹Λղফ͢Δ
  50. // After public function __construct($PaymentManager = null) { $this->manager =

    $PaymentManager ?? new PaymentManager(); } public function charge($order) { $result = $this->manager->charge($order); // ܾࡁγεςϜʹ௨஌ } Constructor Injection ίϯετϥΫλͷҾ਺Ͱ౉͢͜ͱͰɺ Mock΁ͷࠩ͠ସ͑Λ༰қʹ͢Δ - ςετ͠ʹ͍͘ίʔυɿྫ - खಈDIͰີ݁߹Λղফ͢Δ
  51. // mock objectΛ࡞Δ $mock = $this->getMockBuilder(Sample::class) ->setMethods(['update']) ->getMock(); // mock

    objectͷϝιουͷظ଴஋ͱฦ͢஋Λఆٛ $mock->expects($this->once()) ->method('update') ->with($this->equalTo(‘param1')) ->will($this->returnValue(true); // Constructor injection͢Δ৔߹ $target = new Target($mock); IUUQTQIQVOJUEFNBOVBMFOUFTUEPVCMFTIUNM - ςετ͠ʹ͍͘ίʔυɿྫ - खಈDIͰີ݁߹Λղফ͢Δ
  52. // mock objectΛ࡞Δ $mock = $this->getMockBuilder(Sample::class) ->setMethods(['update']) ->getMock(); // mock

    objectͷϝιουͷظ଴஋ͱฦ͢஋Λఆٛ $mock->expects($this->once()) ->method('update') ->with($this->equalTo(‘param1')) ->will($this->returnValue(true); // Constructor injection͢Δ৔߹ $target = new Target($mock);  MockΦϒδΣΫτΛ࡞੒͢Δ (PHPUnit Test Doubles) https://phpunit.de/manual/6.5/en/test-doubles.html - ςετ͠ʹ͍͘ίʔυɿྫ - खಈDIͰີ݁߹Λղফ͢Δ
  53. // mock objectΛ࡞Δ $mock = $this->getMockBuilder(Sample::class) ->setMethods(['update']) ->getMock(); // mock

    objectͷϝιουͷظ଴஋ͱฦ͢஋Λఆٛ $mock->expects($this->once()) ->method('update') ->with($this->equalTo(‘param1')) ->will($this->returnValue(true); // Constructor injection͢Δ৔߹ $target = new Target($mock);  - ςετ͠ʹ͍͘ίʔυɿྫ - खಈDIͰີ݁߹Λղফ͢Δ Constructor InjectionΛߦ͏
  54. • ςετ͠ʹ͍͘ίʔυͷղফʹ͕͔͔࣌ؒ Δ৔߹ • ີ݁߹Λղ͘ͷʹେ͖ͳϦϑΝΫλϦϯάΛཁ͢Δ • ґଘ͍ͯ͠ΔΫϥεͷதͰɺ࣮ࡍʹ֎෦௨৴Λߦ͏ίʔ υΛؚΉͱ͍ͬͨ৔߹ • ςετ͠ʹ͍͘Օॴʹରͯ͠ɺͲ͏खΛೖ

    ΕΔ͔ • runkitΛ׆༻ͯ͠ςετΛॻ͘  - طଘίʔυΛอޢ͢Δٕ๏ɿ2. ϨΨγʔίʔυ - ςετ͠ʹ͍͘ίʔυͷน
  55. • runkit֦ுϞδϡʔϧ • ఆ਺ɾϢʔβʔఆٛؔ਺ ͓ΑͼϢʔβʔఆ ٛΫϥεΛมߋ͢ΔػೳΛఏڙ • ૊ΈࠐΈؔ਺ͷڍಈΛมߋ͍ͨ͠৔߹ͳͲ ʹར༻Ͱ͖Δ 

    IUUQQIQOFUNBOVBMKBJOUSPSVOLJUQIQ - ςετ͠ʹ͍͘ίʔυͷน - runkit
  56. // ର৅ؔ਺ఆٛΛॻ͖׵͑Δ $val = <<<_XML__ <response>success</response> __XML__; runkit_function_copy(‘curl_exec’, ‘curl_exec_org’); runkit_function_redefine(‘curl_exec’,

    ‘’, $val); // ςετର৅ίʔυΛ࣮ߦ $result = $this->Sample->exec(); // ॻ͖׵͑ͨؔ਺ఆٛΛ΋ͱʹ໭͢ runkit_function_remove(‘curl_exec’); runkit_function_copy(‘curl_exec_org’, ‘curl_exec’); runkit_function_remove(‘curl_exec_org’); ؔ਺ఆٛͷόοΫΞοϓΛऔΓɺظ଴͢ΔϨεϙ ϯε($val)Λฦ͢Α͏ʹ࠶ఆٛ͢Δ - ςετ͠ʹ͍͘ίʔυͷน - runkitΛ༻͍ͨςετ
  57. // ର৅ؔ਺ఆٛΛॻ͖׵͑Δ $val = <<<_XML__ <response>success</response> __XML__; runkit_function_copy(‘curl_exec’, ‘curl_exec_org’); runkit_function_redefine(‘curl_exec’,

    ‘’, $val); // ςετର৅ίʔυΛ࣮ߦ $result = $this->Sample->exec(); // ॻ͖׵͑ͨؔ਺ఆٛΛ΋ͱʹ໭͢ runkit_function_remove(‘curl_exec’); runkit_function_copy(‘curl_exec_org’, ‘curl_exec’); runkit_function_remove(‘curl_exec_org’); ςετର৅ίʔυΛ࣮ߦ - ςετ͠ʹ͍͘ίʔυͷน - runkitΛ༻͍ͨςετ
  58. // ର৅ؔ਺ఆٛΛॻ͖׵͑Δ $val = <<<_XML__ <response>success</response> __XML__; runkit_function_copy(‘curl_exec’, ‘curl_exec_org’); runkit_function_redefine(‘curl_exec’,

    ‘’, $val); // ςετର৅ίʔυΛ࣮ߦ $result = $this->Sample->exec(); // ॻ͖׵͑ͨؔ਺ఆٛΛ΋ͱʹ໭͢ runkit_function_remove(‘curl_exec’); runkit_function_copy(‘curl_exec_org’, ‘curl_exec’); runkit_function_remove(‘curl_exec_org’); όοΫΞοϓΛऔ͍ͬͯͨ΋ͱ΋ͱͷؔ਺ఆٛʹ ࠶ఆٛ͠௚͢ - ςετ͠ʹ͍͘ίʔυͷน - runkitΛ༻͍ͨςετ
  59. • ࢖Θͳ͍ʹӽͨ͜͠ͱ͸ͳ͍ • ৽ن࣮૷ͷςετίʔυ͸ɺrunkitར༻Λ લఏͱ͠ͳ͍Α͏ʹप஌্ͨ͠Ͱ࢖༻͢Δ • PHPͷόʔδϣϯʹԠͯ͡ɺʮpeclͰͷ഑ ෍ͳͷ͔ʯ౳ར༻ํ๏͕ҟͳΔ • https://qiita.com/kunit/items/

    43ca86a461d2e5e051cf  - ςετ͠ʹ͍͘ίʔυͷน - runkitར༻ͷ஫ҙ఺
  60. • طଘͷৼΔ෣͍Λ࢓༷ԽςετͰอޢ͢Δ • ௐࠪతϦϑΝΫλϦϯάͰݱঢ়ͷ࣮૷Λཧղ ͢Δ • ີ݁߹Λղফͯ͠ςετΛॻ͖΍͘͢͢Δ • ղ͘ͷʹ࣌ؒͷ͔͔Δίʔυʹରͯ͠͸ runkit֦ு౳Λར༻

     2. ·ͱΊ
  61. 3. ϢχοτςετྔΛ૿΍͢ ࢼΈ

  62. ϢχοτςετྔΛ૿΍͢ࢼΈ • ᴈ໌ظΛա͗ͨޙͷ՝୊ͱͯ͠ɺςετΛॻ ͘ਓɾॻ͔ͳ͍ਓ͕ग़ͯ͘Δ • ։ൃνʔϜͱͯ͠ɺʮϢχοτςετΛॻ͘ จԽʯ͕ඞཁ • ʮςετΛॻ͘ਓʯΛ૿΍͍ͯ͘͠ 

  63. –ΫϦεɾόʔνϟϧஶʰϨΨγʔιϑτ΢ΣΞվળΨΠυʱ “ίʔυ͕ϨΨγʔʹʢͱ͍͏ͷ͸ɺେ ͬ͟ͺʹݴͬͯɺอक͕ࠔ೉ʹʣͳΔʹ ͸ɺଟ͘ͷཧ༝͕͋Γ·͕͢ɺ΄ͱΜͲ ͷݪҼ͸ɺٕज़Ͱ͸ͳ͘ਓؒʹؔ܎ͯ͠ ͍·͢ɻ” https://www.shoeisha.co.jp/book/detail/9784798145143

  64. ςετΛ૿΍্͢Ͱͷน • ςετΛॻ͍ͨ͜ͱ͕ͳ͍ͱɺ࠷ॳͷҰา ͕౿Έग़ͮ͠Β͍ • ͏·͍͔͘ͳ͍ͱ͖ͷɺτϥϒϧγϡʔςΟ ϯάʹ΋͕͔͔࣌ؒΔ 

  65. ରࡦɿςετΛॻ͘োนΛԼ͛Δ • Ϣχοτςετʹ͍ͭͯͷ஌ݟڞ༗ • ࣾ಺ϢχοτςετϋϯζΦϯͷ։࠵ • CakePHPࣗମͷBug Fix • ςετΛॻ͖΍͍͢࢓૊ΈΛ࡞Δ

    
  66. Ϣχοτςετʹ͍ͭͯͷ஌ݟڞ༗  ʮࠔͬͨ͜ͱɺղܾͨ͜͠ͱʯΛυΩϡϝϯτͰڞ༗

  67. Ϣχοτςετʹ͍ͭͯͷ஌ݟڞ༗ • Ϣχοτςετͷॻ͖ํɾ஫ҙ఺ʹ͍ͭͯ ·ͱΊΔυΩϡϝϯτ • ֤ࣗ஌ݟΛखʹೖΕͨਓ͕௥ه͍ͯ͘͠ • ςετʹؔ͢Δ࿩Λ͢Δslack channelͷ༻ ҙ

    
  68. ࣾ಺ϢχοτςετϋϯζΦϯ by @tenkoma 

  69. CakePHPࣗମͷBugFix  IUUQTEFWCMPHUIFCBTFJOFOUSZ CakePHPຊମ΁ͷContribute

  70. ςετΛॻ͖΍͍͢࢓૊Έ • αʔϏεڞ༻ͷςετεΠʔτϓϥάΠϯ • ϑΟΫενϟػߏΛ֦ு • άϩʔόϧม਺؅ཧ • PHPUnit7.xܥػೳͷόοΫϙʔτ •

    ʮassertSameͷdiff͕ݟ΍͘͢͢ΔʯͳͲ 
  71. ςετΛॻ͖΍͍͢࢓૊Έɿར఺ • Ϣχοτςετʹ͓͍ͯɺ๨Ε͕ͪͳલॲ ཧɾޙॲཧͷڞ௨Խ • ֤ςετέʔε࣮૷ऀͷهड़ྔ͕ݮΔ͜ͱͰɺ ςετͷෛ୲ΛͳΔ΂͘ݮΒ͢ 

  72. • ϢχοτςετΛॻ͘จԽΛৢ੒͢Δ • ஌ݟڞ༗ɾ࢓૊ΈʹΑΔԉॿʹΑͬͯɺς ετΛॻ͘োนΛԼ͛Δ  3. ·ͱΊ

  73. 4. Ϣχοτςετ૿Ճʹ͓͚ Δ՝୊ͱରࡦ

  74. Ϣχοτςετ૿Ճʹ͓͚Δ՝୊ͱରࡦ • ഁ୼͠΍͍͢ςετέʔεʹର͢Δରࡦ • ςετίʔυͷϦϑΝΫλϦϯά 

  75. • ςετέʔεͷ਺͕૿͑Δʹ࿈Εͯɺʮ৮ͬ ͍ͯͳ͍Օॴͷςετ͕མͪΔʯέʔεͷ૿ Ճɻ • ʮϩʔΧϧͰ͸௨Δ͕ɺCI؀ڥͰ͸མͪ Δʯͱ͍͏έʔε΋ൃੜ͢Δ • ମݧͱͯ͠ɺʮςετ͕ো֐෺ʯʹͳΔ 

    - Ϣχοτςετ૿Ճʹ͓͚Δ՝୊ͱରࡦ - ՝୊ɿഁ୼͠΍͍͢ςετ
  76. ഁ୼͠΍͍͢ςετྫ • ଞςετέʔεͷӨڹ • ֎෦ཁҼʹӨڹΛड͚Δ • ϥϯμϜੑʹґଘ • FixtureͷมԽʹහײʹམͪΔςετ 

  77. - ഁ୼͠΍͍͢ςετྫ - ଞςετέʔεͷӨڹ • timecopͳͲޙॲཧͰͷย෇͚͕ඞཁͳ΋ͷ ͕ෆ଍͍ͯ͠Δ • τϥϯβΫγϣϯ͕commit͞Ε͍ͯͳ͍ ίʔυʹର͢Δςετέʔε

    
  78. - ഁ୼͠΍͍͢ςετྫ - ֎෦ཁҼͷมԽʹӨڹ͞ΕΔςετ // test༻CloudSearchʹ઀ଓ͢Δ $search = CloudSearchWrapper::factory(); $search->conditions()

    ->keyword(‘test’, ‘title’) ->sort(‘list_order asc’); // test༻CloudSearchʹσʔλొ࿥ $search->documentBatch($this->addJson()); // σʔλొ࿥͞ΕΔ·Ͱ͙͢ʹݕࡧͰ͖ͳ͍ͷͰɺ଴ͭ sleep(3); // ݕࡧ࣮ߦ $result = $search->search($search->conditions()->query());  ωοτϫʔΫঢ়گʹґଘͯ͠མͪΔ
  79. $val = mt_rand(0, 100); $result = $this->Sample->exec($val); $this->assertTrue($result);  “0”͕ग़ͨͱ͖͚ͩམͪΔ

    - ഁ୼͠΍͍͢ςετྫ - ϥϯμϜੑʹґଘ
  80. $data = [‘name’ => ‘hogehoge’]; $result = $this->Sample->saveSample($data); $expected =

    [ ‘id’ => 1, ‘name’ => ‘hogehoge’, ]; $data = ClassRegistry::init(‘Sample’)->find(‘first’, [ ‘conditions’ => [‘name’ => ‘hogehoge’] ]; $this->assertSame($expected, $data);  Sample modelʹରԠ͢ΔϑΟΫενϟʹɺ ϨίʔυΛೖΕΔͱɺ ɹsave࣌ͷid͕auto increment͞ΕམͪΔ - ഁ୼͠΍͍͢ςετྫ - FixtureͷมԽʹහײʹམͪΔςετ
  81. • ίʔυϨϏϡʔʹΑΔݕ஌ • ςετεΠʔτ֦ுʹΑΔԉॿ  - Ϣχοτςετ૿Ճʹ͓͚Δ՝୊ͱରࡦ - ରࡦɿഁ୼͠ʹ͍͘ςετ΁

  82. • ςετʹର͢Δ஌ݟ͕ཷ·͖͍ͬͯͯΔ • ίʔυϨϏϡʔʹͯɺܦݧࡁΈͷʮഁ୼͠ ΍͍͢ςετʯ͕ฆΕ͍ͯͳ͍͔Λ֬ೝ͢ Δ  - ରࡦɿഁ୼͠ʹ͍͘ςετ΁ -

    ίʔυϨϏϡʔʹΑΔݕ஌
  83. • શςετέʔεͰڞ௨ͷFixureΛར༻͢Δ͜ ͱͰɺύζϧతͳFixtureʹͳͬͯ͠·͏ • ֤ςετέʔε͝ͱʹͦΕͧΕFixtureΛ༻ ҙ͢Δػߏ  - ରࡦɿഁ୼͠ʹ͍͘ςετ΁ -

    ςετεΠʔτ֦ுʹΑΔԉॿ
  84. - ςετεΠʔτ֦ுʹΑΔԉॿɿྫ - CakePHP2Ͱͷ֦ுྫʢ1ʣ class UserTest extends AppTestCase { public

    $fixtures = [ 'app.user', ]; public $autoFixtures = false; public function test_canUser_ར༻ՄೳϢʔβʔ(): void { $this->loadFixturesWithRecords([ 'User' => [ UserTestHelper::availableUser, ], ]); $this->assertTrue($this->User->canUse(1)); } } 
  85. - ςετεΠʔτ֦ுʹΑΔԉॿɿྫ - CakePHP2Ͱͷ֦ுྫʢ1ʣ class UserTest extends AppTestCase { public

    $fixtures = [ 'app.user', ]; public $autoFixtures = false; public function test_canUser_ར༻ՄೳϢʔβʔ(): void { $this->loadFixturesWithRecords([ 'User' => [ UserTestHelper::availableUser, ], ]); $this->assertTrue($this->User->canUse(1)); } }  CakePHPͷCakeTestCaseΛ֦ுɻ ඞཁͳςʔϒϧɾϨίʔυΛςετέʔε಺Ͱload͢Δ
  86. - ςετεΠʔτ֦ுʹΑΔԉॿɿྫ - CakePHP2Ͱͷ֦ுྫʢ1ʣ <?php class UserTestHelper { const availableUser

    = [ 'id' => 1, 'name' => 'hogehuga', 'available' => 1, 'created' => '2018-12-15 15:30:00', 'modified' => '2018-12-15 15:30:00', ]; }  ςετέʔε͝ͱʹඞཁͳϨίʔυঢ়ଶΛఆٛ
  87. - ςετεΠʔτ֦ுʹΑΔԉॿɿྫ - CakePHP2Ͱͷ֦ுྫʢ2ʣ class UserTest extends AppTestCase { public

    $fixtures = [ 'app.user', ]; public $autoFixtures = false; public function test_canUser_ར༻ՄೳϢʔβʔ(): void { $this->loadFixturesWithRecords([ 'User' => ‘User/User.php’, ]); $this->assertTrue($this->User->canUse(1)); } }  ϑΝΠϧͰςετέʔεʹඞཁͳϨίʔυΛࢦఆ͢Δ
  88. - ςετεΠʔτ֦ுʹΑΔԉॿɿྫ - CakePHP2Ͱͷ֦ுྫʢ2ʣ <?php return [ [ 'id' =>

    1, 'available' => 1, ] ];  ςετέʔεʹͱͬͯ໌ࣔతʹඞཁͳΧϥϜͷΈ஋Λࢦఆ͢Δɻ ࢦఆ͍ͯ͠ͳ͍ΧϥϜ͸ɺςετ࣮ߦ࣌ʹfzaninotto/Fakerʹ ΑΓμϛʔͷ஋Λࣗಈઃఆ IUUQTHJUIVCDPNG[BOJOPUUP'BLFS
  89. • શςετέʔεڞ௨తͰ͸ͳ͍͕ɺ౰֘ςε τέʔεͰ͸ඞཁͳϨίʔυͷࢦఆ͕༰қ ͱͳͬͨ • ύζϧతͳϑΟΫενϟͷෳࡶԽΛճආͰ ͖Δ  - ରࡦɿഁ୼͠ʹ͍͘ςετ΁

    - ςετέʔε͝ͱͷFixtureͷར఺
  90. • ࠓճͷ࢓༷ԽςετͰ͸ɺʮطଘͷৼΔ෣͍ʯΛ޿ൣғ Ͱอޢͨ͠ • ޿͍͕Ώ͑ʹɺςετ͕ର৅Ϋϥε͔Βԕ͍৔ॴ͕ݪҼ Ͱམͪͨࡍɺಛఆ͕೉͍͠ • “ςετ͕ςετର৅͔Β཭ΕΕ͹཭ΕΔ΄Ͳɺςετͷࣦഊ͕ԿΛҙ ຯ͢Δ͔ͷ൑அ͕೉͘͠ͳΓ·͢ɻ“ʢʰϨΨγʔίʔυվળΨΠ υʱʣ

    • ςετ΋ϝϯςφϯεର৅ͱͯ͠खΛೖΕଓ͚Δඞཁੑ  - Ϣχοτςετ૿Ճʹ͓͚Δ՝୊ͱରࡦ - ՝୊ɿςετίʔυͷϦϑΝΫλϦϯά
  91. • ֤ࣗɺ༻ࣄ͕͋ͬͯमਖ਼͢ΔՕॴʹ͍ͭͯ ͜·ΊͳϦϑΝΫλϦϯάΛ͍ͯ͘͠ • PHPUnitͷػೳΛ༗ޮʹ࢖͏ • લॲཧɾޙॲཧͷෆ଍ͷ௥Ճ • ݟ௨͠Λ্͛ΔͨΊͷςετϔϧύʔԽ •

    ෆཁͳςετέʔεͷ࡟আ  - ՝୊ɿςετίʔυͷϦϑΝΫλϦϯά - ରࡦɿςετίʔυͷϦϑΝΫλϦϯά
  92. • Ϣχοτςετྔ͕૿͑Δ͜ͱͰɺڠௐ͠ ͯഁ୼͠΍͘͢ͳΔ • ίʔυϨϏϡʔɾςετεΠʔτʹΑΔճ ආ • ςετίʔυΛϝϯςφϯεର৅ͱͯ͠Ϧ ϑΝΫλϦϯά͍ͯ͘͠ 

    4. ·ͱΊ
  93. 5. ςετ͕ͳ͍ίʔυΛ ࠶ੜ࢈͠ͳ͍ٕ๏

  94. ςετ͕ͳ͍ίʔυΛ࠶ੜ࢈͠ͳ͍ٕ๏ • ৽نʹ௥Ճ͞ΕΔίʔυʹςετ͕ͳ͍৔ ߹ɺʮϨΨγʔίʔυʯ͕ੜ·Εଓ͚ͯ͠ ·͏ • ςετ͕ͳ͍ίʔυΛ࠶ੜ࢈͠ͳ͍ඞཁੑ 

  95. ςετ͕ͳ͍ίʔυΛ࠶ੜ࢈͞ΕΔཧ༝ • ʮςετΛॻ͘ͷ͕ਏ͍ʯঢ়گ • →ςετΛॻ͘ͷ͕ਏ͍ίʔυઃܭʹͳͬͯ ͍ΔՄೳੑ • →ϓϩμΫγϣϯίʔυΛɺςετ͕ॻ͖ ΍͍͢ઃܭʹ͍ͯ͘͠ඞཁ͕͋Δ 

  96. - ςετ͕ͳ͍ίʔυΛ࠶ੜ࢈͞ΕΔཧ༝ - ςετΛॻ͘ͷ͕ਏ͍ࣄྫ • طଘॲཧʹ੹຿Λ௥Ճͯ͠͠·͏ • طଘΫϥε΁ͷprivateϝιου௥Ճ • ֎෦ཁૉʹରͯ͠ີ݁߹

    • ֎෦APIɾϝʔϧɾSlack ..etc • ੹຿ͷେ͖͍Ϋϥεɾϝιου • ҰͭͷϝιουʹॲཧΛ٧ΊࠐΜͰ͠·͏ 
  97. ςετ͕ͳ͍ίʔυΛ࠶ੜ࢈͠ͳ͍ٕ๏ ࠶ੜ࢈͠ͳ͍ͨΊʹਐΊΔ̎ͭͷΞϓϩʔν 1. UNIX఩ֶ͔ΒֶͿ 2. ςετۦಈ։ൃ 

  98. • ιϑτ΢ΣΞ։ൃʹؔ͢ΔจԽతͳنൣͱ ఩ֶతΞϓϩʔνͷ·ͱ·ΓͷҰͭ • ಛʹೋͭͷΞϓϩʔνΛҙࣝ 1. “ͻͱͭͷ͜ͱΛ͏·͘΍Ε” 2. “Ͱ͖ΔݶΓૣ͘ݪܕʢϓϩτλΠϓʣ Λ࡞Εɻ”

     - ςετ͕ͳ͍ίʔυΛ࠶ੜ࢈͠ͳ͍ٕ๏ - 1. UNIX఩ֶ͔ΒֶͿ
  99. – μάϥεɾϚΩϧϩΠɺUNIXͷ࢛൒ੈل “͜Ε͕UNIXͷ఩ֶͰ͋Δɻ Ұͭͷ͜ͱΛߦ͍ɺ·ͨͦΕΛ͏·͘΍ΔϓϩάϥϜΛॻ͚ ڠௐͯ͠ಈ͘ϓϩάϥϜΛॻ͚ɻ ඪ४ೖग़ྗʢςΩετɾετϦʔϜʣΛѻ͏ϓϩάϥϜΛॻ ͚ɻඪ४ೖग़ྗ͸ීวతΠϯλʔϑΣʔεͳͷͩɻ ” IUUQTKBXJLJQFEJBPSHXJLJ6/*9&#&"%"

  100.  - ʮςετ͕ॻ͖΍͍͢ʯίʔυઃܭ΁ɿ1. UNIX఩ֶ͔ΒֶͿ - 1. “ͻͱͭͷ͜ͱΛ͏·͘΍Ε” • Ұͭͷ͜ͱʹूத͢Δ͜ͱͰෆཁͳ෦෼Λ ແ͍ͯ͘͘͠ɻ

    • ੹຿͕খ͍͞୯Ұ෦඼Λڠௐͯ͠ಈ͔͢
  101. – ϚΠΫɾΨϯΧʔζɺUNIX఩ֶ “Build a prototype as soon as possible.” ʢͰ͖ΔݶΓૣ͘ݪܕʢϓϩτλΠϓʣΛ࡞Εɻʣ

    IUUQTKBXJLJQFEJBPSHXJLJ6/*9&#&"%"
  102.  - ʮςετ͕ॻ͖΍͍͢ʯίʔυઃܭ΁ɿUNIX఩ֶ͔ΒֶͿ - 2. “Ͱ͖ΔݶΓૣ͘ݪܕʢϓϩτλΠϓʣΛ࡞Ε” • ૣ͘࠷௿ݶͷظ଴஋͕ಘΒΕΔ΂ͨॻ͖ͷ ࣮૷Λߦ͏ •

    ࣮૷ମݧ͔Βઃܭʹର͢ΔϑΟʔυόοΫ Λಘͯվળ͍ͯ͘͠ • →ʮςετۦಈ։ൃʯ
  103. • “Test-Driven Development: TDD” • ࣗಈԽ͞ΕͨςετʹΑͬͯ։ൃΛਪ͠ਐΊ Δ • Kent Beck

    ஶʰςετۦಈ։ൃʱ • https://shop.ohmsha.co.jp/shopdetail/000000004967/  - ςετ͕ͳ͍ίʔυΛ࠶ੜ࢈͠ͳ͍ٕ๏ - 2. ςετۦಈ։ൃ
  104. 1. ·ͣ͸ςετΛ̍ͭॻ͘ 2. ͢΂ͯͷςετΛ૸Βͤɺ৽͍͠ςετͷ ࣦഊΛ֬ೝ͢Δ 3. খ͞ͳมߋΛߦ͏ 4. ͢΂ͯͷςετΛ૸Βͤɺશͯ੒ޭ͢Δ͜ ͱΛ֬ೝ͢Δ

    5. ϦϑΝΫλϦϯάΛߦͬͯॏෳΛআڈ͢Δ  - ςετۦಈ։ൃ - ςετۦಈ։ൃͷϦζϜ IUUQTTIPQPINTIBDPKQTIPQEFUBJM
  105. • ౎౓ಈ࡞͢ΔίʔυʹΑͬͯɺઃܭ൑அʹର͢ ΔϑΟʔυόοΫ͕ಘΒΕΔ • ϦϑΝΫλϦϯάʹର͢Δಈ࡞֬ೝͷলྗԽ ͞ΕΔ • ςετ͕ۦಈ͢ΔͨΊɺςετ͕ॻ͖΍͍͢ઃ ܭʹͳΓ΍͍͢ɻڽॖ౓͕ߴ݁͘߹౓͕௿͍ ෦඼Ͱͷߏ੒ͱͳΔ

     - ςετۦಈ։ൃ - ςετۦಈ։ൃͷޮ༻
  106. ৄࡉ͸ɺ΃ͪ͜Μઋ୆(1/26)ʹͯ IUUQTQIQDPOTFOEBJOFU ʮςετΛॻ͘ͷ͕ਏ͘ͳΒͳ͍ςετۦಈ։ൃͷΞϓϩʔνʯ

  107. • ςετΛॻ͘ͷ͕ਏ͍ίʔυઃܭΛճආ͢ Δ • “Ұͭͷ͜ͱΛ͏·͘΍Ε”Λҙࣝ͢Δ • ςετۦಈ։ൃͷΞϓϩʔνʹΑΓɺڽू ౓͕ߴ݁͘߹౓͕௿͍ίʔυઃܭΛ໨ࢦ͢  5.

    ·ͱΊ
  108. ·ͱΊ

  109. ·ͱΊ • ҆શʹαʔϏεΛ੒௕ͤ͞ΔͨΊʹςετΛ ׆༻͢Δ • طଘͷৼΔ෣͍Λ࢓༷ԽςετͰอޢ͢Δ • ςετ͕͠΍͍͢ίʔυઃܭʹ͢Δ͜ͱͰɺ ʮϨΨγʔίʔυʯΛ࠶ੜ࢈͠ͳ͍

  110. ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ Kazuki Higashiguchi / BASE, Inc.