Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
モックの泥沼から脱却するために、あえて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
79
Other Decks in Programming
See All in Programming
tsc.rip を支える技術 / Kyoto.なんか #8
susisu
0
4.4k
[GoCon2026] When Goroutines Are Not Enough: Runtime Locality in High-Throughput Go
takehaya
6
1.9k
AIは賢い。でも実行環境は? CLIおじさんがAI時代に伝えたいこと ~ CLIおじさんがAI時代に伝えたいこと ~
curekoshimizu
1
230
スマート反転とウェブアクセシビリティ
camiha
0
180
型解析で実現する Go の言語内 DSL / Conference に Go! タイムテーブルの歩き方 for Gophers
mazrean
0
140
思考垂れ流し開発 ~音声入力 × AIエージェント × 開発ハーネスによる試行錯誤~
npostring
0
1.1k
DroidKaigi 2026 「個人開発という実験場: Android エンジニアが手にする4つの自由」
slashnephy
0
230
Swift愛好会と私(ウホーイ) / Swift Fan Club and Uhooi
uhooi
0
150
Snowflakeで業務アプリを作ろう。 Snowflakeのアプリ機能解説&実践ガイド
ayumu_yamaguchi
1
220
自分的「カンファレンスの楽しみ方」
syumai
0
200
アクセシビリティから考える情報設計
high_g_engineer
0
350
数年滞っていたダークモード対応をおよそ2週間で完了させる
chigichan24
0
700
Featured
See All Featured
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
Building Applications with DynamoDB
mza
96
7.2k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
35
2.8k
WCS-LA-2024
lcolladotor
0
820
Testing 201, or: Great Expectations
jmmastey
46
8.3k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
3k
Become a Pro
speakerdeck
PRO
31
6.2k
Odyssey Design
rkendrick25
PRO
2
800
The Cult of Friendly URLs
andyhume
79
7k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
49
10k
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
240
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
820
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