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
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
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.3k
LaravelとAWSで_漸進的なプロダクト開発
kazuhei0108
0
180
Laravelのエラーハンドリングをカスタマイズする
kazuhei0108
0
530
サービスコンテナの実践的な活用
kazuhei0108
1
1.2k
クラスを使ってLaravelのviewをキレイにする
kazuhei0108
1
1.8k
自分のLaravel アプリケーション設計晒す
kazuhei0108
0
110
Composerのstabilityの話
kazuhei0108
0
82
Other Decks in Programming
See All in Programming
コードで差別化できない時代の ソフトウェアエンジニアリング / Software Engineering in an Era Where Code Doesn’t Differentiate
kishida
2
180
コードレビューのボトルネックを"する側"と"される側"の両面から解消する
yub0n
2
1.6k
全ての永続トークンを、生まれる前に消し去りたい!
sylph01
2
1k
AmebaブログはKMPから卒業します
kmars0605
0
210
當我們開始不讀 Code - AI Agent 時代,Code Review 與 Clean Code 還剩下什麼?
jame2408
1
280
[Rails World 2026] Durable orchestration on Rails: from continuation to workflow
palkan
1
830
Workers Cache を知る
syumai
0
370
作れる、でも消せるか?──安全に「枯らして消す」機能削除術 / Drain, Then Delete
chobishiba
2
860
RAG の “R” を Swift で覗いてみる 〜「意味から探す」検索の仕組み〜
nao_randd
0
170
AIに “答え“を書かせるのを やめてみた
___akari11
0
120
半永久的に提供し続けられるプライベートクラウドを目指して ― 利用者の認知負荷を抑えるAPI抽象化とハードウェア世代交代の基盤設計
tomokon
0
510
IBM Bob Dojo #1 仕様駆動開発入門
oniak3ibm
PRO
0
410
Featured
See All Featured
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
570
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
330
The Curious Case for Waylosing
cassininazir
1
570
Technical Leadership for Architectural Decision Making
baasie
3
600
Deep Space Network (abreviated)
tonyrice
0
380
How GitHub (no longer) Works
holman
316
150k
A Modern Web Designer's Workflow
chriscoyier
699
190k
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.6k
The Limits of Empathy - UXLibs8
cassininazir
2
730
Mobile First: as difficult as doing things right
swwweet
225
10k
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
540
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