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

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

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

PHPerKaigi2021

Kazuhei Arai

March 27, 2021
Tweet

More Decks by Kazuhei Arai

Other Decks in Programming

Transcript

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

    View Slide

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

    View Slide

  3. ς Ϋ ϊ ϩ δ ʔ ͷ ྗ Ͱ
    M & A ʹ ྲྀ ௨ ֵ ໋ Λ

    View Slide

  4. ."ͷϦΫφϏͷΑ͏ͳαʔϏε
    ങ͍खاۀ͕ങऩχʔζΛܝࡌ͠ɺ

    ചΓख͕ͦΕʹରͯ͠ਃ͠ࠐΉͱ͍͏ܗͷ

    ৽͍͠.ˍ"ϚονϯάϓϥοτϑΥʔϜ

    View Slide

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

    View Slide

  6. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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);
    }

    View Slide

  12. ϞοΫ͠ͳ͍Ϣχοτςετ
    public function testGetHour()
    {
    $time = CommonTime::fromString('2017-01-01 10:21:00');
    $this->assertEquals('10', $time->getHour());
    }
    จࣈྻ͔Β$PNNPO5JNFΫϥεΛ࡞ͬͯɺHFU)PVS͕࣌ؒ
    Λฦ͢͜ͱΛςετ

    View Slide

  13. ϞοΫΛ࢖ͬͨϢχοτςετ
    %#ΞΫηε͍ͯ͠Δ౳ɺΫϥε಺ʹσʔλ͕ด͍ͯ͡
    ͳ͍৔߹ͷςετ͸ϞοΫΛ࢖ͬͯςετ͢Δ

    View Slide

  14. ϞοΫΛ࢖ͬͨϢχοτςετ
    class MessageDomainService
    {

    public function notifyMessage(MessageId $messageId): void
    {
    $message = $this->messageRepository->get($messageId);
    if ($message->needsNotification()) {
    $this->notificationRepository->add($message->notification());
    }
    }
    ϝοηʔδΛऔಘͯ͠ɺඞཁͳΒ௨஌΋௥Ճ͢Δͱ͍͏Α͏
    ͳॲཧ

    View Slide

  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());
    }
    ҰͭҰͭͷσʔλΞΫηε෦෼ΛϞοΫʹͯ͠ɺؔ਺͕ݺ͹
    Ε͍ͯΔ͔Ͳ͏͔Λ֬ೝ͍ͯ͘͠ɻ

    View Slide

  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());
    }
    σʔλϕʔε͔Βऔಘͨ͠σʔλΛ࢖ͬͯɺෳ਺ͷςʔϒϧʹॻ͖
    ࠐΈΛ͍ͯ͘͠Α͏ͳ৔߹ɺͨ͘͞ΜͷσʔλϕʔεΞΫηεΛ
    ϞοΫ͢Δඞཁ͕͋Δɻ

    View Slide

  17. ϞοΫΛ࢖ͬͨϢχοτςετ
    ࣮ࡍͷॲཧ͸͜ΕΑΓ΋Կഒ΋ෳࡶʹͳΓɺςετ
    ίʔυ΋͜ΕΑΓ΋ͣͬͱଟ͘ͳͬͯ͠·͏ɻ
    ίʔυΛॻ͍͍ͯΔͷ͔ςετΛॻ͍͍ͯΔͷ͔෼͔
    Βͳ͍ঢ়ଶɻ

    View Slide

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

    View Slide

  19. Կ͕ѱ͍ͷ͔ʁ

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  23. ϞοΫͷటপ

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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)
    }
    ࣮ࡍͷ%#ʹॻ͖ࠐΜͰɺͦΕΛऔΓग़ͯ͠Ұக͍ͯ͠
    Δ͔֬ೝ͢Δ͚ͩɻͱͯ΋γϯϓϧ

    View Slide

  33. %#ʹͭͳ͍Ͱςετ͢Δͱ͖ͷ໰୊఺
    ɾςετޙͷ෭࡞༻ΛͲ͏΍ͬͯରॲ͢Δ͔
    ɾ࣮ߦ࣌ؒΛͲ͏͢Δ͔

    View Slide

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

    View Slide

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

    View Slide

  36. ςετޙͷ෭࡞༻ΛͲ͏΍ͬͯରॲ͢Δ͔
    αϯϓϧίʔυ͸-BSBWFMΛ࢖ͬͨ΋ͷɻTFUVQ
    ࣌ʹ
    USBOTBDUJPOΛுΓɺUFBS%PXO
    ࣌ʹSPMMCBDL͍ͯ͠Δ
    declare(strict_types=1);
    namespace Tests;
    use Illuminate\Foundation\Testing\DatabaseTransactions;
    abstract class BaseDbIntegrationTest extends TestCase
    {
    use DatabaseTransactions;
    }

    View Slide

  37. ࣮ߦ࣌ؒΛͲ͏͢Δ͔
    Ϣχοτςετ͸଎໋͕͞ɻσʔλϕʔεʹͭͳ͍Ͱ͍
    ͨΒςετ͕஗͘ͳͬͯ͠·͏😅

    View Slide

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

    View Slide

  39. ࣮ߦ࣌ؒΛͲ͏͢Δ͔
    1)16OJUͷઃఆͰςετΛ෼ׂ͠ɺ࣮ߦλΠϛϯάΛௐ੔͢
    Δ͜ͱͰରॲ


    ./tests/Feature


    ./tests/DbIntegration


    ./tests/Unit


    View Slide

  40. ࣮ߦ࣌ؒΛͲ͏͢Δ͔
    $*্Ͱ͸ଞͷछྨͷςετͱฒྻ࣮ߦͰ͖ΔΑ͏ʹઃఆ͠ɺ
    શମͰͷ࣮ߦ࣌ؒʹ͸ӨڹΛ༩͑ͳ͍Α͏ʹ

    View Slide

  41. ·ͱΊ

    View Slide

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

    View Slide

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

    View Slide

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

    IUUQTXXXPSFJMMZDPKQCPPLT

    View Slide