$30 off During Our Annual Pro Sale. View Details »

テストが辛いを解決するテスト駆動開発のアプローチ at PHPカンファレンス仙台2019

テストが辛いを解決するテスト駆動開発のアプローチ at PHPカンファレンス仙台2019

"テストが辛いを解決するテスト駆動開発のアプローチ" at PHPカンファレンス仙台2019

Kazuki Higashiguchi
PRO

January 24, 2019
Tweet

More Decks by Kazuki Higashiguchi

Other Decks in Technology

Transcript

  1. ςετ͕ਏ͍Λղܾ͢Δ ςετۦಈ։ൃ ͷΞϓϩʔν ,B[VLJ)JHBTIJHVDIJ !IHTHUL  1)1ΧϯϑΝϨϯεઋ୆

  2. "CPVUUIJTUBML ࢿྉެ։͋Γ !IHTHULΑΓ5XJUUFS ʹͯγΣΞ

  3. 2VFTUJPO ϢχοτςετΛ ॻ͍͍ͯΔʁ

  4. 2VFTUJPO ͿͬͪΌ͚ ςετΛॻ͘ͷ͕ਏ ͍ʁ

  5. 8IBUUIJTUBMLJT BCPVU w ʮϢχοτςετΛॻ͘ͷ͕ ਏ͍ʯͱ͍͏՝୊ΛݴޠԽ͢ ΔࢼΈ w ՝୊ʹର͢Δղ๏ͱͯ͠ʮς ετۦಈ։ൃʯΛ׆༻͢Δ

  6. 8IBUUIJTUBMLJTOPU BCPVU w ΤϯυπʔΤϯυςετ w 1)16OJUͷ࢖͍ํ w ςετ࣮ߦ؀ڥͷ੔උ

  7. WBS@EVNQ NF  w ౦ޱ࿨ᏻ ,B[VLJ)JHBTIJHVDIJ  w !IHTHUL (JU)VC

    5XJUUFS  w 4FSWFSTJEF&OHJOFFS (P 1)1 FUD  w ॴଐɿ#"4&#"/,גࣜձࣾ w #"4&גࣜձࣾࢠձࣾ
  8. "HFOEB  Ϣχοτςετ͕ਏ͍ཁҼ  ςετۦಈ։ൃͱ͸  ςετۦಈ։ൃΛ׆༻͢Δ  ςετۦಈ։ൃ΁ͷো֐Λ औΓআ͘

     ·ͱΊ
  9. ̍Ϣχοτςετ͕ ਏ͍ཁҼ

  10. Ϣχοτςετͱ͸ w ୯ମςετͱ΋ݺ͹ΕΔ w ϓϩάϥϜΛߏ੒͢Δൺֱతখ͞ͳ୯ҐʢϢχο τʣ͕ݸʑͷػೳΛਖ਼͘͠Ռ͍ͨͯ͠Δ͔Ͳ ͏͔Λݕূ͢Δ w 1)16OJUͳͲͷςετϑϨʔϜϫʔΫΛ༻͍ͯ ࣮ߦ͢Δ

  11. Ϣχοτςετ͕ ਏ͍༷ʑͳཁҼ w ςετͷॻ͖ํ͕Θ͔Βͳ͍ w ৗʹҰࠁҰඵΛ૪͍ͬͯΔ w طଘίʔυʹςετ͕ͳ͍ w ςετΛॻ͘ͷ͕ԯ߷

    w ςετΛॻ͘ͷ͕೉͍͠ίʔ υʹͳΔ w طଘςετ͕։ൃΛ๦͍͛ͯ Δ
  12. w ςετͷॻ͖ํ͕Θ͔Βͳ͍ w ৗʹҰࠁҰඵΛ૪͍ͬͯΔ w طଘίʔυʹςετ͕ͳ͍ w ςετΛॻ͘ͷ͕ԯ߷ w ςετΛॻ͘ͷ͕೉͍͠ίʔ

    υʹͳΔ w طଘςετ͕։ൃΛ๦͍͛ͯ Δ w ςετͷॻ͖ํͷशಘ d$BVTFd d1PTTJCMZ4PMVUJPOd w ϓϩδΣΫτ؅ཧ w ϨΨγʔίʔυվળ w ςετͷॻ͖΍͍͢ઃܭ w Մಡੑɾϝϯςφϯεੑ ͷߴ͍Ϣχοτςετ w ࣮૷தͷςετͷҐஔͮ ͚ͷݟ௚͠
  13. w ςετͷॻ͖ํ͕Θ͔Βͳ͍ w ৗʹҰࠁҰඵΛ૪͍ͬͯΔ w طଘίʔυʹςετ͕ͳ͍ w ςετΛॻ͘ͷ͕ԯ߷ w ςετΛॻ͘ͷ͕೉͍͠ίʔ

    υʹͳΔ w طଘςετ͕։ൃΛ๦͍͛ͯ Δ d$BVTFd d1PTTJCMZ4PMVUJPOd w ςετͷॻ͖ํͷशಘ w ϓϩδΣΫτ؅ཧ w ϨΨγʔίʔυվળ w ςετͷॻ͖΍͍͢ઃܭ w Մಡੑɾϝϯςφϯεੑ ͷߴ͍Ϣχοτςετ w ࣮૷தͷςετͷҐஔͮ ͚ͷݟ௚͠ Focus points
  14. ςετΛॻ͘ͷ͕ԯ߷ w ʮςετΛॻ͘ͷ͕ԯ߷ʯͱ͍͏੠Λฉ͘ࡍɺ ಈ࡞ίʔυΛॻ͍ͨޙʹςετΛॻ͘έʔε ͕ଟ͍ w ಈ࡞ίʔυΛॻ͍͔ͯΒɺςετΛॻ͘ͷ͕ ໘౗ w ࣮૷ͷϦζϜͷதʹϢχοτςετ͕͍ͳ͍

  15. ςετΛॻ͘ͷ͕೉͍͠ίʔυʹͳΔ w ಈ࡞ίʔυ࣮૷ޙɺ͍͟ςετΛॻ͜͏ͱ͠ ͨΒςετ͕ॻ͖ͮΒ͔ͬͨͱ͍͏έʔε͕ ͋Δ w ςετΛॻ͍͍ͯͳ͍ίʔυ͸ɺςετ͕ॻ ͖ͮΒ͍έʔε͕ଟ͍

  16. 4VNNBSZ wϢχοτςετ͕ਏ͍ঢ়گ ʹ͸༷ʑͳཁҼ͕͋Δ wʮϢχοτςετͱ࣮૷ͷ ϦζϜͷ్੾Εʯ͕ɺςε τΛॻ͘ԯ߷͞ΛੜΉ wʮςετΛॻ͖ͮΒ͍ίʔ υʯ͕ɺϢχοτςετΛ ਏ͘͢Δ

  17. ςετۦಈ։ൃͱ͸

  18. ςετۦಈ։ൃͱ͸ w ϓϩάϥϜ։ൃख๏ͷҰछ w ʮಈ࡞͢Δ͖Ε͍ͳίʔυʯΛΰʔϧͱ͢Δ w ϓϩάϥϛϯάதͷෆ҆Λίϯτϩʔϧ͢Δख ๏ w ࣗಈԽ͞ΕͨςετʹΑͬͯ։ൃΛਪ͠ਐΊ

    Δ
  19. 3FE(SFFO3FGBDUPS 3FE Green Refactor 'BJMFEUFTU 1BTTFE 3FGBDUPS

  20. ςετۦಈ։ൃͷαΠΫϧ w ·ͣ͸ςετΛҰͭॻ͘ w ͢΂ͯͷςετΛ૸Βͤɺ৽͍͠ςετͷࣦഊ Λ֬ೝ͢Δ 3FE  w খ͞ͳมߋΛߦ͏

    w ͢΂ͯͷςετΛ૸Βͤɺ͢΂ͯ੒ޭ͢Δ͜ͱ Λ֬ೝ͢Δ (SFFO  w ϦϑΝΫλϦϯάΛߦͬͯॏෳΛআڈ͢Δ 3FGBDUPS
  21. ςετۦಈ։ൃͷਐΊํ w 50%0ϦετΛ࡞੒͢Δ w ඞཁʹͳΓͦ͏ͳςετΛॻ͖ग़͍ͯ͘͠ w ్தͰؾ͕͍ͭͨ՝୊Λ௥ه͍ͯ͘͠ w ςετۦಈ։ൃͷαΠΫϧʢ3FE(SFFO 3FGBDUPS

    Λճ͍ͯ͘͠ w 3FE͔Β(SFFOʹ͢ΔͨΊͷzԾ࣮૷zΛ͠ɺ ૉૣ͘αΠΫϧΛճ͢
  22. %FNPOTUSBUJPO wྫɿ$.4ΞϓϦέʔ γϣϯ wهࣄৄࡉऔಘ"1*Λ࣮ ૷͢Δ

  23. 50%0Ϧετ <>هࣄৄࡉऔಘʹͯ੒ޭϨεϙϯε͕ฦ٫͞ ΕΔ <>هࣄৄࡉऔಘʹͯଘࡏ͢ΔϨίʔυͷ৔߹ɺ هࣄ৘ใ͕ฦ٫͞ΕΔ DEMO ʢࢿྉެ։༻ʣ

  24. ςετΛॻ͘ /** * @test */ public function هࣄৄࡉऔಘʹͯ੒ޭϨεϙϯε͕ฦ٫͞ΕΔ() { $this->configRequest([

    'headers' => [ 'Accept' => 'application/json', ], ]); $this->get('/api/articles/view/first'); $this->assertResponseSuccess(); } DEMO ʢࢿྉެ։༻ʣ
  25. 1PTTJCMZSFMBUFEUP $BLFa$POUSPMMFSa&YDFQUJPOa.JTTJOH"DUJPO& YDFQUJPO"DUJPO"SUJDMFT$POUSPMMFSWJFX  DPVMEOPUCFGPVOE PSJTOPUBDDFTTJCMF 'BJMFEBTTFSUJOHUIBUJTCFUXFFO BOE DEMO ʢࢿྉެ։༻ʣ

  26. খ͞ͳมߋΛߦ͏ class ArticlesController extends AppController { public function view($slug =

    null) { } } DEMO ʢࢿྉެ։༻ʣ
  27. 1PTTJCMZSFMBUFEUP $BLFa7JFXa&YDFQUJPOa.JTTJOH5FNQMBUF&YDF QUJPO5FNQMBUFpMF"QJ"SUJDMFTKTPO WJFXDUQJTNJTTJOH 'BJMFEBTTFSUJOHUIBUJTCFUXFFO BOE DEMO ʢࢿྉެ։༻ʣ

  28. খ͞ͳมߋΛߦ͏ class ArticlesController extends AppController { public function initialize() {

    parent::initialize(); $this->loadComponent('RequestHandler'); } public function view($slug = null) { $this->set([ '_serialize' => ['article'], 'article' => [], ]); } } DEMO ʢࢿྉެ։༻ʣ
  29. 0, UFTUT BTTFSUJPOT DEMO ʢࢿྉެ։༻ʣ

  30. 50%0Ϧετ <Y>هࣄৄࡉऔಘʹͯ੒ޭϨεϙϯε͕ฦ٫͞ ΕΔ <>هࣄৄࡉऔಘʹͯଘࡏ͢ΔϨίʔυͷ৔߹ɺ هࣄ৘ใ͕ฦ٫͞ΕΔ DEMO ʢࢿྉެ։༻ʣ

  31. ςετΛॻ͘ /** * @test */ public function هࣄৄࡉऔಘʹͯଘࡏ͢ΔϨίʔυͷ৔߹ɺهࣄ৘ใ͕ฦ٫͞ΕΔ() { $this->configRequest([

    'headers' => [ 'Accept' => 'application/json', ], ]); $this->get('/api/articles/view/first'); $expected = [ 'article' => [ 'id' => 1, 'user_id' => 1, 'title' => 'First Article', 'slug' => 'first', 'body' => 'First Article Body', 'published' => 1, 'created' => '2018-01-07T15:47:01+00:00', 'modified' => '2018-01-07T15:47:02+00:00', ], ]; $expected = json_encode($expected, JSON_PRETTY_PRINT); $this->assertSame($expected, (string)$this->_response->getBody()); } DEMO ʢࢿྉެ։༻ʣ
  32. DEMO ʢࢿྉެ։༻ʣ 'BJMFEBTTFSUJOHUIBUUXPTUSJOHTBSFJEFOUJDBM

  33. Ծ࣮૷ public function view($slug = null) { // TODO temporary

    implement $article = [ 'id' => 1, 'user_id' => 1, 'title' => 'First Article', 'slug' => 'first', 'body' => 'First Article Body', 'published' => 1, 'created' => '2018-01-07T15:47:01+00:00', 'modified' => '2018-01-07T15:47:02+00:00', ]; $this->set([ '_serialize' => ['article'], 'article' => $article, ]); } DEMO ʢࢿྉެ։༻ʣ
  34. 0, UFTUT BTTFSUJPOT DEMO ʢࢿྉެ։༻ʣ

  35. ϦϑΝΫλϦϯά public function view($slug = null) { $article = $this->Articles->findBySlug($slug)-

    >firstOrFail(); $this->set([ '_serialize' => ['article'], 'article' => $article, ]); } DEMO ʢࢿྉެ։༻ʣ
  36. 0, UFTUT BTTFSUJPOT DEMO ʢࢿྉެ։༻ʣ

  37. 50%0Ϧετ <Y>هࣄৄࡉऔಘʹͯ੒ޭϨεϙϯε͕ฦ٫͞ ΕΔ <Y>هࣄৄࡉऔಘʹͯଘࡏ͢ΔϨίʔυͷ৔߹ɺ هࣄ৘ใ͕ฦ٫͞ΕΔ DEMO ʢࢿྉެ։༻ʣ

  38. w ςετͷॻ͖ํ͕Θ͔Βͳ͍ w ৗʹҰࠁҰඵΛ૪͍ͬͯΔ w طଘίʔυʹςετ͕ͳ͍ w ςετΛॻ͘ͷ͕ԯ߷ w ςετΛॻ͘ͷ͕೉͍͠ίʔ

    υʹͳΔ w طଘςετ͕։ൃΛ๦͍͛ͯ Δ d$BVTFd d1PTTJCMZ4PMVUJPOd w ςετͷॻ͖ํͷशಘ w ϓϩδΣΫτ؅ཧ w ϨΨγʔίʔυվળ w ςετͷॻ͖΍͍͢ઃܭ w Մಡੑɾϝϯςφϯεੑ ͷߴ͍Ϣχοτςετ w ࣮૷தͷςετͷҐஔͮ ͚ͷݟ௚͠ Focus points ৼΓฦΓ
  39. ςετۦಈ։ൃ׆༻ͷํ਑ w ςετۦಈ։ൃͷ͍͔ͭ͘ͷଆ໘Λ༗ޮ׆༻ ͢Δ w ςετΛ࠷ॳʹॻ͘ʢςετϑΝʔετʣ͜ ͱʹΑΓɺʮςετ͕ॻ͖ͮΒ͍ʯίʔυΛ ճආ͢Δ w ςετۦಈ։ൃͷϦζϜΛऔΓೖΕΔ͜ͱͰɺ

    ಈ࡞ίʔυͱςετΛҰͭͷϦζϜͰਐΊΔ
  40. 4VNNBSZ w3FE(SFFO3FGBDUPS ͷϦζϜΛ΋ͬͯਐΊ Δςετۦಈ։ൃ wςετۦಈ։ൃʹΑͬ ͯɺςετ͕ॻ͖ͮΒ ͍ɾԯ߷ͳঢ়گΛճ ආ͢Δ

  41. ςετۦಈ։ൃΛ ׆༻͢Δ

  42. ϢχοτςετΛҙຯ͚ͮΔ w ܽؕͷ͋Δίʔυͷࠞೖ཰ΛԼ͛Δ w ৺ཧతෆ҆ΛԼ͛Δ w lςετ͕௨͍ͬͯΔ͔Βյ͍ͯ͠ͳ͍͸ͣz w ༐׶ͳϦϑΝΫλϦϯά w

    ઃܭͷิॿಓ۩
  43. ઃܭͷิॿಓ۩ͱͯ͠ͷςετ w Ϣχοτςετ͔Βɺಈ࡞ίʔυͷઃܭʹͭ ͍ͯɺϑΟʔυόοΫΛಘΔ w ςετΛઌʹॻ͘͜ͱͰɺʮςετͷ͠΍͢ ͍ίʔυʯΛॻ͘ΪϒεΛ෇͚Δ w ʮςετͷॻ͖ʹ͘͞ʯ͔Βઃܭʹର͢Δҧ ࿨ײΛټΈऔΔ

  44. $BTF4UVEZ ઃܭͷ ϑΟʔυόοΫΛ ςετέʔε͔Β ಘΔ

  45. $BTF4UVEZ w ໰͍߹ΘͤอଘػೳΛ࣮૷͢Δ w ʮλΠτϧʯɾʮຊจʯɾʮϝʔϧΞυϨεʯɾ ʮΫϥΠΞϯτͷ*1ΞυϨεʯΛอଘ͓ͯ͘͠

  46. 50%0Ϧετ <Y>໰͍߹ΘͤϖʔδʹΞΫηεͰ͖Δ <Y>໰͍߹Θͤอଘ੒ޭ࣌Ұཡϖʔδ΁ϦμΠ ϨΫτ͢Δ <>໰͍߹Θͤͨ͠಺༰͕JORVJSJFTςʔϒϧʹ อଘ͞ΕΔ

  47. ݱ࣌఺ͷςετ /** * @test */ public function ໰͍߹ΘͤϖʔδʹΞΫηεͰ͖Δ() { $this->get('/inquiries/add');

    $this->assertResponseOk(); } /** * @test */ public function ໰͍߹Θͤอଘ੒ޭ࣌Ұཡϖʔδ΁ϦμΠϨΫτ͢Δ() { $this->enableCsrfToken(); $this->enableSecurityToken(); $data = [ 'title' => 'sample', 'body' => 'sample', 'email' => 'hgsgtk@gmail.com', ]; $this->post('/inquiries/add', $data); $this->assertResponseSuccess(); $this->assertRedirect('/inquiries'); }
  48. ݱ࣌఺ͷ࣮૷ public function add() { $inquiry = $this->Inquiries->newEntity(); if ($this->request->is('post'))

    { // TODO save inquiry data return $this->redirect(['action' => 'index']); } $this->set(compact('inquiry')); }
  49. 50%0Ϧετ <Y>໰͍߹ΘͤϖʔδʹΞΫηεͰ͖Δ <Y>໰͍߹Θͤอଘ੒ޭ࣌Ұཡϖʔδ΁ϦμΠ ϨΫτ͢Δ <>໰͍߹Θͤͨ͠಺༰͕JORVJSJFTςʔϒϧʹ อଘ͞ΕΔ

  50. ·ͣ͸ςετΛॻ͘ /** * @test */ public function ໰͍߹Θͤͨ͠಺༰͕inquiriesςʔϒϧʹอଘ͞ΕΔ() { $this->enableCsrfToken();

    $this->enableSecurityToken(); $this->configRequest([ 'environment' => ['REMOTE_ADDR' => '12.34.56.78'], ]); $data = [ 'title' => 'sample', 'body' => 'sample', 'email' => 'hgsgtk@gmail.com', ]; $this->post('/inquiries/add', $data); /** @var Inquiry $saved_inquiry */ $saved_inquiry = TableRegistry::getTableLocator() ->get('inquiries')->find() ->where(['title' => 'sample'])->first(); $this->assertInstanceOf('\App\Model\Entity\Inquiry', $saved_inquiry); }
  51. 'BJMFEBTTFSUJOHUIBUOVMMJTBOJOTUBODFPGDMBTT la"QQa.PEFMa&OUJUZa*ORVJSZ 5FTUT "TTFSUJPOT 'BJMVSFT

  52. ςετΛ௨ͨ͢ΊͷԾ࣮૷ public function add() { $inquiry = $this->Inquiries->newEntity(); if ($this->request->is('post'))

    { // FIXME temporary $inquiry->title = 'sample'; $inquiry->body = 'sample'; $inquiry->email = 'hgsgtk@gmail.com'; $inquiry->client_ip = ’12.34.56.78'; $this->Inquiries->save($inquiry); return $this->redirect(['action' => 'index']); } $this->set(compact('inquiry')); }
  53. 0, UFTUT BTTFSUJPOT

  54. 3FGBDUPSJOH w ظ଴஋ͷςετΛ࡞੒͠ɺςετ͕௨ΔԾ࣮૷Λͨ͠ w Ծ࣮૷ΛϦϑΝΫλϦϯά͢Δ

  55. ࣮૷ऀ͕಄ʹු͔Μ࣮ͩ૷ public function saveWithIp(Inquiry $entity, \Cake\Http\ServerRequest $request) { $entity->client_ip =

    $request->clientIp(); return $this->save($entity); } w .PEFM૚ʹϝιουΛ࡞੒ w ϦΫΤετΦϒδΣΫτΛड͚औͬͯอଘ
  56. ςετΛॻ͘ /** * @test */ public function ໰͍߹Θͤͨ͠಺༰͕inquiriesςʔϒϧʹอଘ͞ΕΔ() { $inquiry

    = $this->Inquiries->newEntity( [ 'title' => 'sample', 'body' => 'sample', 'email' => 'example@example.com', ] ); $request = new \Cake\Http\ServerRequest('/inquiries/ add'); $actual = $this->Inquiries->saveWithIp($inquiry, $request); // Assert something } w ϝιου࡞੒Λ૝ఆ͍ͯ͠Δ.PEFMʹςετΛॻ͘
  57. ςετ͔Βҧ࿨ײΛټΈऔΔ /** * @test */ public function ໰͍߹Θͤͨ͠಺༰͕inquiriesςʔϒϧʹอଘ͞ΕΔ() { $inquiry

    = $this->Inquiries->newEntity( [ 'title' => 'sample', 'body' => 'sample', 'email' => 'example@example.com', ] ); $request = new \Cake\Http\ServerRequest('/inquiries/ add'); $actual = $this->Inquiries->saveWithIp($inquiry, $request); // Assert something } ϢχοτςετΛॻͨ͘Ίʹɺ ςετ༻ͷϦΫΤετΛੜ੒͢Δख͕ؒൃੜ ͍ͯ͠Δ
  58. ҧ࿨ײ͔Βઃܭ൑அ͢Δ /** * @test */ public function ໰͍߹Θͤͨ͠಺༰͕inquiriesςʔϒϧʹอଘ͞ΕΔ() { $inquiry

    = $this->Inquiries->newEntity( [ 'title' => 'sample', 'body' => 'sample', 'email' => 'example@example.com', ] ); $request = new \Cake\Http\ServerRequest('/inquiries/ add'); $actual = $this->Inquiries->saveWithIp($inquiry, $request); // Assert something } ϞσϧΫϥε͕ɺ ϦΫΤετΫϥεʹґଘ͍ͯ͠Δઃܭ͸ɺ ΍Ίͨ΄͏͕ྑͦ͞͏ͩ
  59. ςετΛม͑ͯΈΔ /** * @test */ public function ໰͍߹Θͤͨ͠಺༰͕inquiriesςʔϒϧʹอଘ͞ΕΔ() { $inquiry

    = $this->Inquiries->newEntity( [ 'title' => 'sample', 'body' => 'sample', 'email' => 'example@example.com', ‘client_ip' => ‘171.0.0.1’, ] ); $actual = $this->Inquiries->saveWithIp($inquiry); // Assert something } ϦΫΤετΫϥε΁ͷґଘΛɺ ςετίʔυͷஈ֊Ͱഉআͨ͠ɻ
  60. ςετΛม͑ͯΈΔ /** * @test */ public function ໰͍߹Θͤͨ͠಺༰͕inquiriesςʔϒϧʹอଘ͞ΕΔ() { $inquiry

    = $this->Inquiries->newEntity( [ 'title' => 'sample', 'body' => 'sample', 'email' => 'example@example.com', ‘client_ip' => ‘171.0.0.1’, ] ); $actual = $this->Inquiries->saveWithIp($inquiry); // Assert something } ݁ՌతʹɺΤϯςΟςΟΛอଘ͢Δ͚ͩʹ ͳͬͨɻ ϝιουΛ࡞੒͢Δ͜ͱ͕ͦ΋ͦ΋ෆཁ ͱ൑அɻ
  61. Ծ࣮૷Λॻ͖׵͑Δ public function add() { $inquiry = $this->Inquiries->newEntity(); if ($this->request->is('post'))

    { $inquiry = $this->Inquiries->patchEntity($inquiry, $this- >request->getData()); $inquiry->client_ip = $this->request->clientIp(); if (!$this->Inquiries->save($inquiry)) { // TODO error handling } return $this->redirect(['action' => 'index']); } $this->set(compact('inquiry')); }
  62. 0, UFTUT BTTFSUJPOT

  63. 50%0Ϧετ <Y>໰͍߹ΘͤϖʔδʹΞΫηεͰ͖Δ <Y>໰͍߹Θͤอଘ੒ޭ࣌Ұཡϖʔδ΁ϦμΠ ϨΫτ͢Δ <Y>໰͍߹Θͤͨ͠಺༰͕JORVJSJFTςʔϒϧʹ อଘ͞ΕΔ

  64. $BTF4UVEZ͔ΒֶͿ w ςετۦಈ։ൃͰਐΊΔதͰɺʮςετͷॻ ͖ʹ͘͞ʯΛᄿ͚͗ͭͨ w ಘͨϑΟʔυόοΫʹΑͬͯɺʮςετ͕ਏ͍ ίʔυʯΛճආͨ͠

  65. ҧ࿨ײʹର͢Δײ౓Λ্͛Δ w ʮҧ࿨ײΛײ͡Δʯʹ͋ͨΓײ౓Λ͍͔͋͛ͯ ͳ͍ͱ͍͚ͳ͍ w ʮςετ͕͔͚Δʯίʔυ͕ɺʮςετͷॻ͖΍ ͍͢ʯίʔυʹͳΔΘ͚Ͱ͸ͳ͍ w ઃܭࢥ૝ɾٕ๏ͳͲΛซͤͯҙ͓ࣝͯ͘͠ඞཁੑ w

    ҙࣝ͠΍͍͢ͱ͜Ζ͔Β࢝ΊͯΈΔ
  66. ςετͷॻ͖΍͍͢ίʔυ w Ϋϥεͷґଘؔ܎͕໌ࣔతͰஔ͖׵͑΍͍͢ w ੹຿͕໌֬Ͱɺݺͼग़͠ɾݕূ͕؆୯ʹͰ͖ Δ w ͍ΘΏΔʮૄ݁߹͔ͭߴڽूʯ

  67. ҧ࿨ײΛײ͡ΔͨΊʹҙࣝ͢Δ͜ͱ Ұͭͷ͜ͱΛ͏·͘΍Ε͍ͯΔ͔

  68. rμάϥεɾϚΩϧϩΠ6/*9ͷ࢛൒ੈل l͜Ε͕6/*9ͷ఩ֶͰ͋Δɻ Ұͭͷ͜ͱΛߦ͍ɺ·ͨͦΕΛ͏·͘΍ΔϓϩάϥϜ Λॻ͚ɻ ڠௐͯ͠ಈ͘ϓϩάϥϜΛॻ͚ɻz https://ja.wikipedia.org/wiki/UNIX఩ֶ

  69. ҧ࿨ײΛײ͡ΔͨΊʹҙࣝ͢Δ͜ͱ ҰจͰΫϥεΛઆ໌Ͱ͖Δ͔

  70. ҰจͰΫϥεΛઆ໌Ͱ͖Δ͔ w ʮΫϥε͕࣮ࡍʹԿΛ͍ͯ͠Δͷ͔͕໌֬Ͱ ͋Δ͔ʯΛਤΔ w "/%ɾ03ɾ#65Λ࢖Θͣʹઆ໌Ͱ͖Δ͔ w ࢖ͬͯ͠·ͬͨ৔߹ɺෳ਺ͷ੹຿͕ࠞࡏͯ͠ ͍ΔՄೳੑ͕͋Δ

  71. $BTF4UVEZ ΞΧ΢ϯτొ࿥

  72. 50%0Ϧετ w <>ΞΧ΢ϯτ৘ใ͕σʔλϕʔεʹอଘ͞Ε Δ w <>ొ࿥׬ྃϝʔϧΛૹ৴͞ΕΔ

  73. ࣦഊ͢ΔςετΛॻ͘ /** * @test */ public function ΞΧ΢ϯτ৘ใ͕σʔλϕʔεʹอଘ͞ΕΔ() { $result

    = $this->AccountService->register(); // σʔλϕʔεʹอଘ͞Εͨ஋ΛΞαʔτ͢Δ }
  74. ςετΛ௨࣮͢૷Λ͢Δ class AccountService { public function register() { // ΞΧ΢ϯτ৘ใอଘॲཧ

    } }
  75. 50%0Ϧετ w <Y>ΞΧ΢ϯτ৘ใ͕σʔλϕʔεʹอଘ͞Ε Δ w <>ొ࿥׬ྃϝʔϧΛૹ৴͞ΕΔ

  76. ͞ΒʹςετΛ௥Ճ͢Δ /** * @test */ public function ΞΧ΢ϯτ৘ใ͕σʔλϕʔεʹอଘ͞ΕΔ() { $result

    = $this->AccountService->register(); // σʔλϕʔεʹอଘ͞Εͨ஋ΛΞαʔτ͢Δ } /** * @test */ public function ొ࿥׬ྃϝʔϧΛૹ৴͞ΕΔ() { $result = $this->AccountService->register(); // ొ࿥׬ྃϝʔϧ͕ૹ৴͞Εͨ͜ͱΛΞαʔτ͢Δ }
  77. SFHJTUFS ͕ԿΛ΍Ζ͏ͱ͍ͯ͠Δ͔Λҙࣝ͢Δ w SFHJTUFS ϝιου͸ɺҰͭͷ͜ͱΛ͏·͘΍ Ε͍ͯΔ͔ʁ w ʮΞΧ΢ϯτ৘ใΛσʔλϕʔεʹอଘ͠ɺ ͦͯ͠ొ࿥׬ྃϝʔϧΛૹ৴͢Δʯ w

    ̎ͭͷॲཧΛಉ࣌ʹ΍Ζ͏ͱ͍ͯ͠Δ
  78. SFHJTUFS ͷςετͷॻ͖ͮΒ͞ w ϝʔϧૹ৴ॲཧΛςετ͍ͨ͠৔߹ɺΞΧ΢ ϯτͷσʔλϕʔεอଘॲཧͱҰॹʹςετ ͠ͳ͚Ε͹ͳΒͳ͍ w ҟͳΔଐੑͷৼΔ෣͍͕ີʹ݁߹ͯ͠͠·͏ ͱɺಛఆͷৼΔ෣͍ʹରͯ͠ςετ͕ॻ͖ͮ Β͘ͳΔ

  79. 50%0Ϧετ΁ୀආ͢Δ w ςετίʔυ͔ΒɺSFHJTUFS ͸΍Γ͍͗ͯ͢ Δ͜ͱ͕Θ͔ͬͨ w ͔͠͠ɺ·ͣ͸໨ͷલͷ3FEΛ(SFFOʹ͢Δ w Ծ࣮૷ͱͯ͢͢͠Ίɺղܾ͢΂͖ߏ଄্ͷ໰ ୊Λ50%0Ϧετʹ௥Ճ͢Δ

  80. 50%0Ϧετ w <Y>ΞΧ΢ϯτ৘ใ͕σʔλϕʔεʹอଘ͞Ε Δ w <>ొ࿥׬ྃϝʔϧΛૹ৴͞ΕΔ w <>ొ࿥׬ྃϝʔϧૹ৴͸ɺ"DDPVOU4FSWJDFΫ ϥεͷ੹຿͔Β௥͍ग़͢

  81. ςετΛ௨࣮͢૷Λ͢Δ class AccountService { public function register() { // ΞΧ΢ϯτ৘ใอଘॲཧ

    ɹɹɹɹ // ϝʔϧૹ৴ॲཧ } }
  82. 50%0Ϧετ w <Y>ΞΧ΢ϯτ৘ใ͕σʔλϕʔεʹอଘ͞Ε Δ w <Y>ొ࿥׬ྃϝʔϧΛૹ৴͞ΕΔ w <>ొ࿥׬ྃϝʔϧૹ৴͸ɺSFHJTUFS ͷ੹຿͔ Β௥͍ग़͢

  83. ࣦഊ͢ΔςετΛॻ͘ /** * @test */ public function ొ࿥׬ྃϝʔϧΛૹ৴͞ΕΔ() { $result

    = $this->AccountMailer->send(); // ొ࿥׬ྃϝʔϧ͕ૹ৴͞Εͨ͜ͱΛΞαʔτ͢Δ } w ϝʔϧૹ৴Λߦ͏"DDPVOU.BJMFSΫϥεͷςε τΛ࡞੒ɺ"DDPVOU4FSWJDF5FTU͔Βςετϝιο υΛҠಈ͢Δ
  84. ςετΛ௨࣮͢૷Λ͢Δ class AccountMailer { public function send(Account $account): bool {

    // ϝʔϧૹ৴ } }
  85. 50%0Ϧετ w <Y>ΞΧ΢ϯτ৘ใ͕σʔλϕʔεʹอଘ͞Ε Δ w <Y>ొ࿥׬ྃϝʔϧΛૹ৴͞ΕΔ w <Y>ొ࿥׬ྃϝʔϧૹ৴͸ɺSFHJTUFS ͷ੹຿ ͔Β௥͍ग़͢

  86. $BTF4UVEZ͔ΒֶͿ w ςετίʔυɾಈ࡞ίʔυΛॻ͖ͳ͕ΒɺʮҰ ͭͷ͜ͱΛ͏·͘΍Ε͍ͯΔ͔ʯΛҙࣝͨ͠ w ్தͰ΍Γ͍͗ͯ͢ΔϝιουΛ՝୊ͱͯ͠ ೝࣝ͠ɺ50%0ʹͨ͠ w ΍Γ͗ͨ͢ϝιουΛϦϑΝΫλϦϯάͨ͠

  87. 4VNNBSZ wઃܭͷิॿಓ۩ͱͯ͠Ϣ χοτςετΛ༻͍Δ wςετίʔυͷॻ͖ʹ͘ ͔͞Βɺઃܭʹର͢Δҧ ࿨ײΛټΈऔΔ wټΈऔͬͨҧ࿨ײΛϦ ϑΝΫλϦϯάͰղফ͢ Δ

  88. ςετۦಈ։ൃ΁ͷ ো֐ΛऔΓআ͘

  89. ςετۦಈ։ൃ΁ͷো֐ w ςετۦಈ։ൃΛ࣮ફ͢ΔͨΊͷো֐ΛऔΓ আ͘ w Ұͭͷέʔεͱͯ͠ɺςετ͕ͳ͍ίʔυʹͭ ͍ͯऔΓѻ͏

  90. $BTF4UVEZ ςετ͕ͳ͍ίʔυ

  91. ςετ͕ͳ͍ίʔυ public function index() { $articles = $this->Articles->find('all'); $this->set([ '_serialize'

    => ['articles'], 'articles' => $articles, ]); } w هࣄҰཡΛKTPOͰฦ٫͢Δγϯϓϧͳ"1* w lެ։͍ͯ͠Δ QVCMJTIFE zهࣄͷΈฦ٫͢ΔมߋΛ૝ఆ w ͔͠͠ɺલ೚ऀʹΑΔςετίʔυ͸ॻ͔Ε͍ͯͳ͔ͬͨ
  92. ςετۦಈ։ൃͷ౔ඨʹ্͛Δ w ·ͣ͸ɺطଘͷৼΔ෣͍Λอޢ͢Δςετίʔ υΛॻ͘ʢ࢓༷Խςετʣ w อޢͨ͠ޙʹςετۦಈ։ൃͷαΠΫϧΛ࣮ફ ͢Δ

  93. ࢓༷Խςετ wl$IBSBDUFSJ[BUJPOUFTUz wίʔυͷৼΔ෣͍Λ໌Β͔ʹ͢Δςετ

  94. ࢓༷Խςετͷखॱ  ςετίʔυͷதͰର৅ͷίʔυΛݺͼग़͢  ࣦഊ͢ΔͱΘ͔͍ͬͯΔද໌Λॻ͘  ࣦഊͨ݁͠Ռ͔Β࣮ࡍͷৼΔ෣͍Λ֬ೝ͢Δ  ίʔυ͕࣮ݱ͢ΔৼΔ෣͍Λظ଴͢ΔΑ͏ʹɺ ςετΛมߋ͢Δ

     ʙΛ܁Γฦ͢
  95. ର৅ίʔυΛݺͼग़͢ /** * @test */ public function هࣄҰཡऔಘʹͯهࣄҰཡ͕ฦ٫͞ΕΔ() { $this->configRequest([

    'headers' => [ 'Accept' => 'application/json', ], ]); $this->get('/api/articles/index'); }
  96. ࣦഊ͢Δද໌Λߦ͏ /** * @test */ public function هࣄҰཡऔಘʹͯهࣄҰཡ͕ฦ٫͞ΕΔ() { $this->configRequest([

    'headers' => [ 'Accept' => 'application/json', ], ]); $this->get('/api/articles/index'); $expected = json_encode([], JSON_PRETTY_PRINT); $this->assertSame($expected, (string)$this- >_response->getBody()); }
  97. ࣦഊͨ݁͠Ռ͔Β࣮ࡍͷৼΔ෣͍Λ֬ೝ͢Δ 'BJMFEBTTFSUJOHUIBUUXPTUSJOHTBSFJEFOUJDBM

  98. ςετΛมߋ͢Δ $expected = [ 'articles' => [ [ 'id' =>

    1, 'user_id' => 1, 'title' => 'First Published Article', 'slug' => 'first-published-article', 'body' => 'First Published Body', 'published' => 1, 'created' => '2018-01-07T15:47:01+00:00', 'modified' => '2018-01-07T15:47:02+00:00', ], [ 'id' => 2, 'user_id' => 1, 'title' => 'Unpublished Article', 'slug' => 'unpublished-article', 'body' => 'Unpublished Article Body', 'published' => 0, 'created' => '2018-01-07T15:47:01+00:00', 'modified' => '2018-01-07T15:47:02+00:00', ], ], ]; $expected = json_encode($expected, JSON_PRETTY_PRINT); $this->assertSame($expected, (string)$this->_response->getBody());
  99. 0, UFTU BTTFSUJPO

  100. มߋ͍ͨ͠ৼΔ෣͍Λςετʹॻ͘ $expected = [ 'articles' => [ [ 'id' =>

    1, 'user_id' => 1, 'title' => 'First Published Article', 'slug' => 'first-published-article', 'body' => 'First Published Body', 'published' => 1, 'created' => '2018-01-07T15:47:01+00:00', 'modified' => '2018-01-07T15:47:02+00:00', ], ], ]; $expected = json_encode($expected, JSON_PRETTY_PRINT); $this->assertSame($expected, (string)$this->_response->getBody()); w ެ։த QVCMJTIFE ͷΈฦ٫͞ΕΔৼΔ෣͍ Λظ଴஋ͱͯ͠ઃఆ͢Δ
  101. ςετ͕ࣦഊ͢Δ 'BJMFEBTTFSUJOHUIBUUXPTUSJOHTBSFJEFOUJDBM

  102. ςετΛ௨࣮͢૷Λߦ͏ public function index() { $articles = $this->Articles ->find() ->where(['published'

    => 1]) ->all(); $this->set([ '_serialize' => ['articles'], 'articles' => $articles, ]); }
  103. 0, UFTU BTTFSUJPO

  104. 4VNNBSZ wςετ͕ͳ͍ͱ͍͏ো ֐ʹରͯ͠͸ɺ࢓༷Խ ςετʹΑͬͯอޢ͢ Δ wͦͷޙɺςετۦಈ։ ൃͷαΠΫϧ΁ਐΊΔ

  105. ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ɻ 5BML4VNNBSZ w ʮςετ͕ਏ͍ʯʹର͢Δ༷ʑͳཁҼ͔Βɺ ʮςετΛॻ͘ԯ߷͞ʯɾʮςετ͕ॻ͖ͮ Β͍ίʔυʹͳΔέʔεʯʹϑΥʔΧεͨ͠ w ςετۦಈ։ൃͷϦζϜʹΑͬͯɺςετͱಈ ࡞ίʔυΛҰͭͷϦζϜͰਐΊΔ w

    ઃܭͷิॿಓ۩ͱͯ͠ϢχοτςετΛ׆༻ ͢Δ͜ͱͰɺςετ͕ॻ͖ͮΒ͍ίʔυΛճ ආ͢Δ