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
340
Predefined Interfacesを使って便利な独自クラスを作りましょう
kazuhei0108
0
3.1k
LaravelとAWSで_漸進的なプロダクト開発
kazuhei0108
0
170
Laravelのエラーハンドリングをカスタマイズする
kazuhei0108
0
510
サービスコンテナの実践的な活用
kazuhei0108
1
1.2k
クラスを使ってLaravelのviewをキレイにする
kazuhei0108
1
1.7k
自分のLaravel アプリケーション設計晒す
kazuhei0108
0
99
Composerのstabilityの話
kazuhei0108
0
72
Other Decks in Programming
See All in Programming
Spec Driven Development | AI Summit Lisbon
danielsogl
PRO
0
180
JJUG CCC 2026 Spring: JSpecify で実現する Kotlin フレンドリーな Java API 設計
ternbusty
1
160
AI 時代のソフトウェア設計の学び方
masuda220
PRO
29
12k
AIで効率化できた業務・日常
ochtum
0
120
Javaの型とAI時代に型が大事な理由 / java types and type in AI era
kishida
2
120
LLM本来の能力を解き放つサンドボックス技術とAI民主化への適用
yukukotani
3
3.6k
Technical Debt: Understanding it Rightly, Engaging it Rightly #LaravelLiveJP
shogogg
0
220
Modding RubyKaigi for Myself
yui_knk
0
920
Developing with AI Agents — Codex, Claude Code & Cowork Practical Guide
x5gtrn
PRO
0
1.2k
AI駆動開発で崩れていくコードベースを立て直す
kyoko_nr_nr
1
450
AI時代のUIはどこへ行く?その2!
yusukebe
21
7k
過去最大のMCPアップデート! 2026-07-28 RC版の謎に迫る
licux
6
240
Featured
See All Featured
HDC tutorial
michielstock
2
700
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.2k
Facilitating Awesome Meetings
lara
57
7k
Making Projects Easy
brettharned
120
6.7k
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
250
How STYLIGHT went responsive
nonsquared
100
6.2k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
Product Roadmaps are Hard
iamctodd
PRO
55
12k
Making the Leap to Tech Lead
cromwellryan
135
9.9k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
290
VelocityConf: Rendering Performance Case Studies
addyosmani
333
25k
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
2.8k
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