Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
モックの泥沼から脱却するために、あえてDBにつないでテストしている話
Search
Kazuhei Arai
March 27, 2021
Programming
3.5k
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
モックの泥沼から脱却するために、あえてDBにつないでテストしている話
PHPerKaigi2021
Kazuhei Arai
March 27, 2021
More Decks by Kazuhei Arai
See All by Kazuhei Arai
CTOがプロダクトを管轄して、変わり始めたスクラム開発
kazuhei0108
0
350
Predefined Interfacesを使って便利な独自クラスを作りましょう
kazuhei0108
0
3.2k
LaravelとAWSで_漸進的なプロダクト開発
kazuhei0108
0
170
Laravelのエラーハンドリングをカスタマイズする
kazuhei0108
0
520
サービスコンテナの実践的な活用
kazuhei0108
1
1.2k
クラスを使ってLaravelのviewをキレイにする
kazuhei0108
1
1.8k
自分のLaravel アプリケーション設計晒す
kazuhei0108
0
110
Composerのstabilityの話
kazuhei0108
0
78
Other Decks in Programming
See All in Programming
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
630
自動化したのに回らないテスト運用の壁ーAI時代の品質責任と生産性
mfunaki
1
140
リアルな遅延を測る仕様
kota_yata
1
120
為什麼你並不需要ViewModel / No, you don't need a ViewModel
lovee
1
500
Japan Community Day at Kubecon + CloudNativeCon Japan 2026: Learning Container Privilege Control by Building My Own Low-Level Container Runtime
ternbusty
1
160
20260722_microCMSで考える、AI時代のコンテンツ運用設計
yosh1
0
420
【QA Test Talk Vol.8】AI-DLC による Whole Team Approach の加速
pkshadeck
PRO
0
200
Jindong: Introducing Declarative Haptics in Compose Multiplatform
l2hyunwoo
0
120
「寝てても仕事が進む」Claude Codeで組む第二の脳
tomoyafujita2016
0
340
【やさしく解説 設計編・中級 #6】良いアーキテクチャとは ~ 一本の登り道の、行き先 ~
panda728
PRO
0
220
AIを紡ぐPMのお話
swdtkuy
0
110
AI時代に設計が 最大の生産性レバーになる 意図駆動開発とデータを消さない設計|Don't Delete Your Data or Your Intent — Design as the Deepest Lever in the AI Era
tomohisa
1
1k
Featured
See All Featured
Raft: Consensus for Rubyists
vanstee
141
7.6k
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
63
45k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
Fireside Chat
paigeccino
42
4k
Navigating Team Friction
lara
192
16k
Large-scale JavaScript Application Architecture
addyosmani
515
110k
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
370
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
700
How Software Deployment tools have changed in the past 20 years
geshan
1
34k
Designing Powerful Visuals for Engaging Learning
tmiket
1
500
Transcript
!LB[VIFJ !LB[VIFJ@@ ϞοΫͷటপ͔Β٫͢ΔͨΊʹɺ ͋͑ͯ%#ʹͭͳ͍Ͱςετ͍ͯ͠Δ 1)1FS,BJHJ
ࣗݾհ ߥҪฏ!LB[VIFJ גࣜձࣾ."Ϋϥυ$50 ৽॓ޚԓελʔτΞοϓ
ς Ϋ ϊ ϩ δ ʔ ͷ ྗ Ͱ M
& A ʹ ྲྀ ௨ ֵ ໋ Λ
."ͷϦΫφϏͷΑ͏ͳαʔϏε ങ͍खاۀ͕ങऩχʔζΛܝࡌ͠ɺ ചΓख͕ͦΕʹରͯ͠ਃ͠ࠐΉͱ͍͏ܗͷ ৽͍͠.ˍ"ϚονϯάϓϥοτϑΥʔϜ
͍ͬͯΔٕज़ɾπʔϧ GSPOUFOE CBDLFOE NJEEMFXBSF JOGSB UPPMT
None
࣍ w ϞοΫΛͬͨϢχοτςετͷ w ͋͑ͯɺ%#ʹͭͳ͍Ͱςετ͢Δ w ·ͱΊ
ϞοΫΛͬͨ Ϣχοτςετͷ
Ϣχοτςετʹ͍ͭͯ ϢχοτςετɺϝιουؔͳͲখ͞ͳϢχοτ୯Ґ ʹߜΓࠐΜͩࣗಈςετɻݱతͳϓϩάϥϛϯάʹ͔ܽͤ ͳ͍
ϞοΫ͠ͳ͍Ϣχοτςετ ୯ҰͷΫϥεʹσʔλͱϩδοΫ͕ด͍ͯ͡Δͷ ؆୯ʹςετग़དྷΔɻ
ϞοΫ͠ͳ͍Ϣχοτςετ 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); }
ϞοΫ͠ͳ͍Ϣχοτςετ public function testGetHour() { $time = CommonTime::fromString('2017-01-01 10:21:00'); $this->assertEquals('10',
$time->getHour()); } จࣈྻ͔Β$PNNPO5JNFΫϥεΛ࡞ͬͯɺHFU)PVS͕࣌ؒ Λฦ͢͜ͱΛςετ
ϞοΫΛͬͨϢχοτςετ %#ΞΫηε͍ͯ͠ΔɺΫϥεʹσʔλ͕ด͍ͯ͡ ͳ͍߹ͷςετϞοΫΛͬͯςετ͢Δ
ϞοΫΛͬͨϢχοτςετ class MessageDomainService { public function notifyMessage(MessageId $messageId): void
{ $message = $this->messageRepository->get($messageId); if ($message->needsNotification()) { $this->notificationRepository->add($message->notification()); } } ϝοηʔδΛऔಘͯ͠ɺඞཁͳΒ௨Ճ͢Δͱ͍͏Α͏ ͳॲཧ
ϞοΫΛͬͨϢχοτςετ 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()); } ҰͭҰͭͷσʔλΞΫηε෦ΛϞοΫʹͯ͠ɺ͕ؔݺ Ε͍ͯΔ͔Ͳ͏͔Λ֬ೝ͍ͯ͘͠ɻ
ϞοΫΛͬͨϢχοτςετ 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()); } σʔλϕʔε͔Βऔಘͨ͠σʔλΛͬͯɺෳͷςʔϒϧʹॻ͖ ࠐΈΛ͍ͯ͘͠Α͏ͳ߹ɺͨ͘͞ΜͷσʔλϕʔεΞΫηεΛ ϞοΫ͢Δඞཁ͕͋Δɻ
ϞοΫΛͬͨϢχοτςετ ࣮ࡍͷॲཧ͜ΕΑΓԿഒෳࡶʹͳΓɺςετ ίʔυ͜ΕΑΓͣͬͱଟ͘ͳͬͯ͠·͏ɻ ίʔυΛॻ͍͍ͯΔͷ͔ςετΛॻ͍͍ͯΔͷ͔͔ Βͳ͍ঢ়ଶɻ
ϞοΫΛͬͨϢχοτςετ
Կ͕ѱ͍ͷ͔ʁ
ςετͷີ݁߹ ϝιου ଞΫϥεͷݺͼग़͠ ଞΫϥεͷݺͼग़͠ ଞΫϥεͷݺͼग़͠ ˡϞοΫ ˡϞοΫ ˡϞοΫ ςετͷີ݁߹͕ى͖͍ͯΔɻϞοΫΛͬͨςετςετ ͕ϝιουͷத·Ͱৄͬͯ͘͠͠·͍ͬͯΔͱ͍͏͜ͱɻ
ςετͷີ݁߹ ϝιου ଞΫϥεͷݺͼग़͠ ଞΫϥεͷݺͼग़͠ ଞΫϥεͷݺͼग़͠ ˡϞοΫ ˡϞοΫ ˡϞοΫ ςετϓϩμΫτίʔυͱີ݁߹͢Ε͢Δ΄ͲյΕ ͘͢ͳΔɻଞΫϥεͷมߋͰςετ͕յΕͯ͠·͏
ςετͷີ݁߹ ϝιου ଞΫϥεͷݺͼग़͠ ଞΫϥεͷݺͼग़͠ ଞΫϥεͷݺͼग़͠ ˡϞοΫ ˡϞοΫ ˡϞοΫ ϞοΫΛ͗ͯ͢͠ϓϩμΫτίʔυ͕ςετͱͯ͠ มߋग़དྷͳ͍ঢ়ଶΛϞοΫͷటপͱ͍͏
ϞοΫͷటপ
ςετͷີ݁߹ ϝιου "HFU "VQEBUF #VQEBUF ˡςετ ˡςετ ˡςετ ࣮ࡍɺϞοΫ͠·͘Δͱɺϝιου͕ݺΕͯΔॱ൪͘Β͍͔͠ ςετग़དྷͳ͍ͷͰʁͪΌΜͱಈ͍͍ͯΔͱอূͰ͖Δͷ͔ʁ
ςετͷछྨ ϞοΫΛ͑͏΄ͲɺςετϗϫΠτϘοΫε ςετʹ͍͍ۙͮͯ͘ɻ શͯͷ݅Λ௨ͯ͠ɺΧόϨοδΛ্͍͛ͨͷ߹ ʹ༗༻͕ͩɺγϯϓϧʹڍಈΛ֬ೝ͍ͨ͠ͱ͖ʹ ϒϥοΫϘοΫεςετʹ͍ͨ͠ɻ
ϗϫΠτϘοΫεςετ ϝιου "HFU "VQEBUF #VQEBUF ˡςετ ˡςετ ˡςετ ͦΕͧΕͷ͕ؔͪΌΜͱݺΕ͍ͯͯɺਖ਼͍͠ذ ʹೖ͍ͬͯΔ͜ͱΛςετ͢Δ
ϒϥοΫϘοΫεςετ ϝιου தΘ͔Βͳ͍͕ɺΠϯϓοτͱΞτϓοτ͕อ ূ͞Ε͍ͯΔঢ়ଶ ˢ ςετ Πϯϓοτ Ξτϓοτ
ϒϥοΫϘοΫεςετ ϝιου ͜ΕʹΑͬͯɺϓϩμΫτίʔυͱςετ͕ಠཱ͠ɺς ετΛ͍͡ΒͣʹίʔυΛมߋ͢Δ͜ͱ͕ग़དྷΔ ˢ ςετ Πϯϓοτ Ξτϓοτ
ςετͷछྨ ϒϥοΫϘοΫεςετʹ͍ͨ͠ʂ😆
͋͑ͯɺ%#ʹͭͳ͙
͋͑ͯɺ%#ʹͭͳ͙ ϝιου ΠϯϓοτͱΞτϓοτΛ%#͔Βऔಘ͢Εɺϒ ϥοΫϘοΫεςετ͕࣮ݱͰ͖Δ ˢ ςετ %# %#
͋͑ͯɺ%#ʹͭͳ͙ public function testNotifyMessage() { $needsNotifyMessage = new Message(...); $domainService
= app()->make(MessageDomainService::class); $domainService->notifyMessage($needsNotifyMessage->id()); $notification = $this->notificationRepository->first(); $this->assertEquals($needsNotifyMessage->notification(), $notification) } ࣮ࡍͷ%#ʹॻ͖ࠐΜͰɺͦΕΛऔΓग़ͯ͠Ұக͍ͯ͠ Δ͔֬ೝ͢Δ͚ͩɻͱͯγϯϓϧ
%#ʹͭͳ͍Ͱςετ͢Δͱ͖ͷ ɾςετޙͷ෭࡞༻ΛͲ͏ͬͯରॲ͢Δ͔ ɾ࣮ߦ࣌ؒΛͲ͏͢Δ͔
ςετޙͷ෭࡞༻ΛͲ͏ͬͯରॲ͢Δ͔ ςετҰͭҰ͕ͭऴΘΔʹσʔλϕʔεͷঢ়ଶΛ͠ ͍ͨɻ ςετΛ࣮ߦ͢ΔʹσʔλϕʔεʹॳظσʔλΛ༻ҙ ͍ͯͨ͠Βɺςετͷ࣮ߦ࣌ؒͷຆͲ͕σʔλͷ༻ҙ ʹͳͬͯ͠·͏😅
ςετޙͷ෭࡞༻ΛͲ͏ͬͯରॲ͢Δ͔ %#ͷτϥϯβΫγϣϯΛ׆༻͢Δ👏
ςετޙͷ෭࡞༻ΛͲ͏ͬͯରॲ͢Δ͔ αϯϓϧίʔυ-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; }
࣮ߦ࣌ؒΛͲ͏͢Δ͔ Ϣχοτςετ໋͕͞ɻσʔλϕʔεʹͭͳ͍Ͱ͍ ͨΒςετ͕͘ͳͬͯ͠·͏😅
࣮ߦ࣌ؒΛͲ͏͢Δ͔ %#ʹͭͳ͙ํ͕ܨ͕ͳ͍ΑΓ͍ͷํͳ͍ͱׂΓ Δ😅࣮ߦͷํΛͯ͠ରॲ
࣮ߦ࣌ؒΛͲ͏͢Δ͔ 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>
࣮ߦ࣌ؒΛͲ͏͢Δ͔ $*্Ͱଞͷछྨͷςετͱฒྻ࣮ߦͰ͖ΔΑ͏ʹઃఆ͠ɺ શମͰͷ࣮ߦ࣌ؒʹӨڹΛ༩͑ͳ͍Α͏ʹ
·ͱΊ
·ͱΊ ɾϞοΫΛͨ͘͞Μ͏ςετɺϓϩμΫτίʔυͱςετ ͕ີ݁߹ͯ͠ϞοΫͷటপʹϋϚͬͯ͠·͏ɻ ɾ͋͑ͯ%#ʹͭͳ͙͜ͱͰϓϩμΫτίʔυͱςετ͕ಠཱ ͠ɺΠϯϓοτͱΞτϓοτΛ֬ೝ͢Δ͚ͩͷγϯϓϧͳς ετʹͳΔ ɾ%#ʹͭͳ͍Ͱςετ͢ΔͨΊͷػೳҙ֎ͱ༻ҙ͞Εͯ ͓ΓɺΕग़དྷΔ
ҙॻ͖ ϞοΫΛ͏ͷΛৗʹΊͨ΄͏͕ྑ͍ͱ͍͏͜ͱͰ͋Γ ·ͤΜɻ࣮ࡍʹϞοΫΛͬͨํ͕ྑ͍έʔεͱͯଟ͍Ͱ ͢ɻ ͨͩɺϞοΫΛΘͳ͍Ͱςετ͢Δํ๏͋ΔΑɺͱ͍͏ Ͱͨ͠ɻ
ࢀߟॻ੶ ॳΊͯͷࣗಈςετ03FJMMZ+BQBO IUUQTXXXPSFJMMZDPKQCPPLT