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

モックの泥沼から脱却するために、あえてDBにつないでテストしている話

 モックの泥沼から脱却するために、あえてDBにつないでテストしている話

PHPerKaigi2021

9184d05c3493636df20a38b8bcfd66df?s=128

Kazuhei Arai

March 27, 2021
Tweet

Transcript

  1. !LB[VIFJ !LB[VIFJ@@ ϞοΫͷటপ͔Β୤٫͢ΔͨΊʹɺ ͋͑ͯ%#ʹͭͳ͍Ͱςετ͍ͯ͠Δ࿩ 1)1FS,BJHJ 

  2. ࣗݾ঺հ ߥҪ࿨ฏ!LB[VIFJ גࣜձࣾ."Ϋϥ΢υ$50 ৽॓ޚԓελʔτΞοϓ

  3. ς Ϋ ϊ ϩ δ ʔ ͷ ྗ Ͱ M

    & A ʹ ྲྀ ௨ ֵ ໋ Λ
  4. ."ͷϦΫφϏͷΑ͏ͳαʔϏε ങ͍खاۀ͕ങऩχʔζΛܝࡌ͠ɺ
 ചΓख͕ͦΕʹରͯ͠ਃ͠ࠐΉͱ͍͏ܗͷ
 ৽͍͠.ˍ"ϚονϯάϓϥοτϑΥʔϜ

  5. ࢖͍ͬͯΔٕज़ɾπʔϧ GSPOUFOE CBDLFOE NJEEMFXBSF JOGSB UPPMT

  6. None
  7. ໨࣍ w ϞοΫΛ࢖ͬͨϢχοτςετͷ໰୊఺ w ͋͑ͯɺ%#ʹͭͳ͍Ͱςετ͢Δ w ·ͱΊ

  8. ϞοΫΛ࢖ͬͨ Ϣχοτςετͷ໰୊఺

  9. Ϣχοτςετʹ͍ͭͯ Ϣχοτςετ͸ɺϝιου΍ؔ਺ͳͲখ͞ͳϢχοτ୯Ґ ʹߜΓࠐΜͩࣗಈςετɻݱ୅తͳϓϩάϥϛϯάʹ͔ܽͤ ͳ͍

  10. ϞοΫ͠ͳ͍Ϣχοτςετ ୯ҰͷΫϥεʹσʔλͱϩδοΫ͕ด͍ͯ͡Δ΋ͷ͸ ؆୯ʹςετग़དྷΔɻ

  11. ϞοΫ͠ͳ͍Ϣχοτςετ class CommonTime { 
 public function __construct(int $timestamp) {

    $this->timestamp = $timestamp; } 
 public static function fromString($string) { return new static(strtotime($string)); } 
 public function getHour(): string { return date('H', $this->timestamp); }
  12. ϞοΫ͠ͳ͍Ϣχοτςετ public function testGetHour() { $time = CommonTime::fromString('2017-01-01 10:21:00'); $this->assertEquals('10',

    $time->getHour()); } จࣈྻ͔Β$PNNPO5JNFΫϥεΛ࡞ͬͯɺHFU)PVS͕࣌ؒ Λฦ͢͜ͱΛςετ
  13. ϞοΫΛ࢖ͬͨϢχοτςετ %#ΞΫηε͍ͯ͠Δ౳ɺΫϥε಺ʹσʔλ͕ด͍ͯ͡ ͳ͍৔߹ͷςετ͸ϞοΫΛ࢖ͬͯςετ͢Δ

  14. ϞοΫΛ࢖ͬͨϢχοτςετ class MessageDomainService { 
 public function notifyMessage(MessageId $messageId): void

    { $message = $this->messageRepository->get($messageId); if ($message->needsNotification()) { $this->notificationRepository->add($message->notification()); } } ϝοηʔδΛऔಘͯ͠ɺඞཁͳΒ௨஌΋௥Ճ͢Δͱ͍͏Α͏ ͳॲཧ
  15. ϞοΫΛ࢖ͬͨϢχοτςετ public function testNotifyMessage() { $needsNotifyMessage = new Message(...); $this->mock(MessageRepository::class,

    function ($mock) use ($needsNotifyMessage) { $mock->shouldReceive('get') ->andReturn($needsNotifyMessage); }); $this->mock(NotificationRepository::class, function ($mock) use ($needsNotifyMessage) { $mock->shouldReceive('add') ->with($needsNotifyMessage->notification()); }); $domainService = app()->make(MessageDomainService::class); $domainService->notifyMessage($needsNotifyMessage->id()); } ҰͭҰͭͷσʔλΞΫηε෦෼ΛϞοΫʹͯ͠ɺؔ਺͕ݺ͹ Ε͍ͯΔ͔Ͳ͏͔Λ֬ೝ͍ͯ͘͠ɻ
  16. ϞοΫΛ࢖ͬͨϢχοτςετ public function testNotifyMessage() { $needsNotifyMessage = new Message(...); $this->mock(MessageRepository::class,

    function ($mock) use ($needsNotifyMessage) { $mock->shouldReceive('get') ->andReturn($needsNotifyMessage); }); $this->mock(NotificationRepository::class, function ($mock) use ($needsNotifyMessage) { $mock->shouldReceive('add') ->with($needsNotifyMessage->notification()); }); $domainService = app()->make(MessageDomainService::class); $domainService->notifyMessage($needsNotifyMessage->id()); } σʔλϕʔε͔Βऔಘͨ͠σʔλΛ࢖ͬͯɺෳ਺ͷςʔϒϧʹॻ͖ ࠐΈΛ͍ͯ͘͠Α͏ͳ৔߹ɺͨ͘͞ΜͷσʔλϕʔεΞΫηεΛ ϞοΫ͢Δඞཁ͕͋Δɻ
  17. ϞοΫΛ࢖ͬͨϢχοτςετ ࣮ࡍͷॲཧ͸͜ΕΑΓ΋Կഒ΋ෳࡶʹͳΓɺςετ ίʔυ΋͜ΕΑΓ΋ͣͬͱଟ͘ͳͬͯ͠·͏ɻ ίʔυΛॻ͍͍ͯΔͷ͔ςετΛॻ͍͍ͯΔͷ͔෼͔ Βͳ͍ঢ়ଶɻ

  18. ϞοΫΛ࢖ͬͨϢχοτςετ

  19. Կ͕ѱ͍ͷ͔ʁ

  20. ςετͷີ݁߹ ϝιου ଞΫϥεͷݺͼग़͠ ଞΫϥεͷݺͼग़͠ ଞΫϥεͷݺͼग़͠ ˡϞοΫ ˡϞοΫ ˡϞοΫ ςετͷີ݁߹͕ى͖͍ͯΔɻϞοΫΛ࢖ͬͨςετ͸ςετ ͕ϝιουͷத਎·Ͱৄ͘͠஌ͬͯ͠·͍ͬͯΔͱ͍͏͜ͱɻ

  21. ςετͷີ݁߹ ϝιου ଞΫϥεͷݺͼग़͠ ଞΫϥεͷݺͼग़͠ ଞΫϥεͷݺͼग़͠ ˡϞοΫ ˡϞοΫ ˡϞοΫ ςετ͸ϓϩμΫτίʔυͱີ݁߹͢Ε͹͢Δ΄ͲյΕ ΍͘͢ͳΔɻଞΫϥεͷมߋͰςετ͕յΕͯ͠·͏

  22. ςετͷີ݁߹ ϝιου ଞΫϥεͷݺͼग़͠ ଞΫϥεͷݺͼग़͠ ଞΫϥεͷݺͼग़͠ ˡϞοΫ ˡϞοΫ ˡϞοΫ ϞοΫΛ͗ͯ͢͠ϓϩμΫτίʔυ͕ςετͱ෼཭ͯ͠ มߋग़དྷͳ͍ঢ়ଶΛϞοΫͷటপͱ͍͏

  23. ϞοΫͷటপ

  24. ςετͷີ݁߹ ϝιου "HFU "VQEBUF #VQEBUF ˡςετ ˡςετ ˡςετ ࣮ࡍɺϞοΫ͠·͘Δͱɺϝιου͕ݺ͹ΕͯΔॱ൪͘Β͍͔͠ ςετग़དྷͳ͍ͷͰ͸ʁͪΌΜͱಈ͍͍ͯΔͱอূͰ͖Δͷ͔ʁ

  25. ςετͷछྨ ϞοΫΛ࢖͑͹࢖͏΄Ͳɺςετ͸ϗϫΠτϘοΫε ςετʹ͍͍ۙͮͯ͘ɻ શͯͷ৚݅Λ௨ͯ͠ɺΧόϨοδΛ্͍͛ͨ౳ͷ৔߹ ʹ͸༗༻͕ͩɺγϯϓϧʹڍಈΛ֬ೝ͍ͨ͠ͱ͖ʹ͸ ϒϥοΫϘοΫεςετʹ͍ͨ͠ɻ

  26. ϗϫΠτϘοΫεςετ ϝιου "HFU "VQEBUF #VQEBUF ˡςετ ˡςετ ˡςετ ͦΕͧΕͷؔ਺͕ͪΌΜͱݺ͹Ε͍ͯͯɺਖ਼͍͠෼ذ ʹೖ͍ͬͯΔ͜ͱΛςετ͢Δ

  27. ϒϥοΫϘοΫεςετ ϝιου த਎͸Θ͔Βͳ͍͕ɺΠϯϓοτͱΞ΢τϓοτ͕อ ূ͞Ε͍ͯΔঢ়ଶ ˢ ςετ Πϯϓοτ Ξ΢τϓοτ

  28. ϒϥοΫϘοΫεςετ ϝιου ͜ΕʹΑͬͯɺϓϩμΫτίʔυͱςετ͕ಠཱ͠ɺς ετΛ͍͡ΒͣʹίʔυΛมߋ͢Δ͜ͱ͕ग़དྷΔ ˢ ςετ Πϯϓοτ Ξ΢τϓοτ

  29. ςετͷछྨ ϒϥοΫϘοΫεςετʹ͍ͨ͠ʂ😆

  30. ͋͑ͯɺ%#ʹͭͳ͙

  31. ͋͑ͯɺ%#ʹͭͳ͙ ϝιου ΠϯϓοτͱΞ΢τϓοτΛ%#͔Βऔಘ͢Ε͹ɺϒ ϥοΫϘοΫεςετ͕࣮ݱͰ͖Δ ˢ ςετ %# %#

  32. ͋͑ͯɺ%#ʹͭͳ͙ public function testNotifyMessage() { $needsNotifyMessage = new Message(...); $domainService

    = app()->make(MessageDomainService::class); $domainService->notifyMessage($needsNotifyMessage->id());
 
 $notification = $this->notificationRepository->first(); $this->assertEquals($needsNotifyMessage->notification(), $notification) } ࣮ࡍͷ%#ʹॻ͖ࠐΜͰɺͦΕΛऔΓग़ͯ͠Ұக͍ͯ͠ Δ͔֬ೝ͢Δ͚ͩɻͱͯ΋γϯϓϧ
  33. %#ʹͭͳ͍Ͱςετ͢Δͱ͖ͷ໰୊఺ ɾςετޙͷ෭࡞༻ΛͲ͏΍ͬͯରॲ͢Δ͔ ɾ࣮ߦ࣌ؒΛͲ͏͢Δ͔

  34. ςετޙͷ෭࡞༻ΛͲ͏΍ͬͯରॲ͢Δ͔ ςετҰͭҰ͕ͭऴΘΔ౓ʹσʔλϕʔεͷঢ়ଶΛ໭͠ ͍ͨɻ ςετΛ࣮ߦ͢Δ౓ʹσʔλϕʔεʹॳظσʔλΛ༻ҙ ͍ͯͨ͠Βɺςετͷ࣮ߦ࣌ؒͷຆͲ͕σʔλͷ༻ҙ ʹͳͬͯ͠·͏😅

  35. ςετޙͷ෭࡞༻ΛͲ͏΍ͬͯରॲ͢Δ͔ %#ͷτϥϯβΫγϣϯΛ׆༻͢Δ👏

  36. ςετޙͷ෭࡞༻ΛͲ͏΍ͬͯରॲ͢Δ͔ αϯϓϧίʔυ͸-BSBWFMΛ࢖ͬͨ΋ͷɻTFUVQ ࣌ʹ USBOTBDUJPOΛுΓɺUFBS%PXO ࣌ʹSPMMCBDL͍ͯ͠Δ <?php declare(strict_types=1); namespace Tests; use

    Illuminate\Foundation\Testing\DatabaseTransactions; abstract class BaseDbIntegrationTest extends TestCase { use DatabaseTransactions; }
  37. ࣮ߦ࣌ؒΛͲ͏͢Δ͔ Ϣχοτςετ͸଎໋͕͞ɻσʔλϕʔεʹͭͳ͍Ͱ͍ ͨΒςετ͕஗͘ͳͬͯ͠·͏😅

  38. ࣮ߦ࣌ؒΛͲ͏͢Δ͔ %#ʹͭͳ͙ํ͕ܨ͕ͳ͍ΑΓ஗͍ͷ͸࢓ํͳ͍ͱׂΓ ੾Δ😅࣮ߦͷ࢓ํΛ޻෉ͯ͠ରॲ

  39. ࣮ߦ࣌ؒΛͲ͏͢Δ͔ 1)16OJUͷઃఆͰςετΛ෼ׂ͠ɺ࣮ߦλΠϛϯάΛௐ੔͢ Δ͜ͱͰରॲ <testsuites> <testsuite name="Feature"> <directory suffix="Test.php">./tests/Feature</directory> </testsuite> <testsuite

    name="DbIntegration"> <directory suffix="Test.php">./tests/DbIntegration</directory> </testsuite> <testsuite name="Unit"> <directory suffix="Test.php">./tests/Unit</directory> </testsuite> </testsuites>
  40. ࣮ߦ࣌ؒΛͲ͏͢Δ͔ $*্Ͱ͸ଞͷछྨͷςετͱฒྻ࣮ߦͰ͖ΔΑ͏ʹઃఆ͠ɺ શମͰͷ࣮ߦ࣌ؒʹ͸ӨڹΛ༩͑ͳ͍Α͏ʹ

  41. ·ͱΊ

  42. ·ͱΊ ɾϞοΫΛͨ͘͞Μ࢖͏ςετ͸ɺϓϩμΫτίʔυͱςετ ͕ີ݁߹ͯ͠ϞοΫͷటপʹϋϚͬͯ͠·͏ɻ ɾ͋͑ͯ%#ʹͭͳ͙͜ͱͰϓϩμΫτίʔυͱςετ͕ಠཱ ͠ɺΠϯϓοτͱΞ΢τϓοτΛ֬ೝ͢Δ͚ͩͷγϯϓϧͳς ετʹͳΔ ɾ%#ʹͭͳ͍Ͱςετ͢ΔͨΊͷػೳ౳΋ҙ֎ͱ༻ҙ͞Εͯ ͓Γɺ΍Ε͹ग़དྷΔ

  43. ஫ҙॻ͖ ϞοΫΛ࢖͏ͷΛৗʹ΍Ίͨ΄͏͕ྑ͍ͱ͍͏͜ͱͰ͸͋Γ ·ͤΜɻ࣮ࡍʹϞοΫΛ࢖ͬͨํ͕ྑ͍έʔε΋ͱͯ΋ଟ͍Ͱ ͢ɻ ͨͩɺϞοΫΛ࢖Θͳ͍Ͱςετ͢Δํ๏΋͋ΔΑɺͱ͍͏ ࿩Ͱͨ͠ɻ

  44. ࢀߟॻ੶ ॳΊͯͷࣗಈςετ03FJMMZ+BQBO
 IUUQTXXXPSFJMMZDPKQCPPLT