Lock in $30 Savings on PRO—Offer Ends Soon! ⏳
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Datetime tests with cakephp/chronos
Search
hideki kinjyo
PRO
March 31, 2019
Programming
0
1.1k
Datetime tests with cakephp/chronos
#phperkaigi 2019でのLT内容です。
cakephp/chronosを利用して強いテスタビリティを手に入れる話
hideki kinjyo
PRO
March 31, 2019
Tweet
Share
More Decks by hideki kinjyo
See All by hideki kinjyo
手軽に積ん読を増やすには?/読みたい本と付き合うには?
o0h
PRO
1
170
symfony/mcp-bundleで、既存アプリケーションもお手軽にMCPサーバー化
o0h
PRO
1
47
組織もソフトウェアも難しく考えない、もっとシンプルな考え方で設計する #phpconfuk
o0h
PRO
10
4.9k
Composerが「依存解決」のためにどんな工夫をしているか #phpcon
o0h
PRO
1
600
Composerの依存解決 #phpstudy
o0h
PRO
0
150
「影響が少ない」を自分の目でみてみる
o0h
PRO
3
1.9k
PHPによる"非"構造化プログラミング入門 -本当に熱いスパゲティコードを求めて- #phperkaigi
o0h
PRO
0
1.8k
もう少しテストを書きたいんじゃ〜 #phpstudy
o0h
PRO
23
5.3k
『テスト書いた方が開発が早いじゃん』を解き明かす #phpcon_nagoya
o0h
PRO
9
4.2k
Other Decks in Programming
See All in Programming
Why Kotlin? 電子カルテを Kotlin で開発する理由 / Why Kotlin? at Henry
agatan
2
6.9k
ID管理機能開発の裏側 高速にSaaS連携を実現したチームのAI活用編
atzzcokek
0
210
WebRTC、 綺麗に見るか滑らかに見るか
sublimer
1
160
【Streamlit x Snowflake】データ基盤からアプリ開発・AI活用まで、すべてをSnowflake内で実現
ayumu_yamaguchi
1
120
SwiftUIで本格音ゲー実装してみた
hypebeans
0
110
バックエンドエンジニアによる Amebaブログ K8s 基盤への CronJobの導入・運用経験
sunabig
0
140
全員アーキテクトで挑む、 巨大で高密度なドメインの紐解き方
agatan
8
20k
社内オペレーション改善のためのTypeScript / TSKaigi Hokuriku 2025
dachi023
1
560
sbt 2
xuwei_k
0
260
C-Shared Buildで突破するAI Agent バックテストの壁
po3rin
0
380
dnx で実行できるコマンド、作ってみました
tomohisa
0
140
251126 TestState APIってなんだっけ?Step Functionsテストどう変わる?
east_takumi
0
310
Featured
See All Featured
What's in a price? How to price your products and services
michaelherold
246
12k
The Cult of Friendly URLs
andyhume
79
6.7k
Scaling GitHub
holman
464
140k
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
Facilitating Awesome Meetings
lara
57
6.7k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
5.7k
The Invisible Side of Design
smashingmag
302
51k
Large-scale JavaScript Application Architecture
addyosmani
515
110k
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.5k
Visualization
eitanlees
150
16k
Unsuck your backbone
ammeep
671
58k
The Language of Interfaces
destraynor
162
25k
Transcript
࣌Λࢧ͢ΔPHP #phperkaigi 2019.03.31 Hideki Kinjyo twitter: @o0h_ / github: o0h
ಥͰ͕͢
Έͳ͞Μࢥ͍·ͤΜ͔
͋ʙɺ͕࣌ؒͱ·Ε͍͍ͷʹɻ
Ͱ͢ΑͶʁ
ͦΕɺPHPͰͰ͖ΔΑʂ
ຊͷ͝հ
cakephp/chronos
ࣗݾհ • ίωώτגࣜձࣾ • αʔόʔαΠυΤϯδχΞ • ओʹCakePHPͳͲ • ࠷ۙɺ{ॳ}ॻ੶Λࣥච͠·ͨ͠ ͡Ί·ͯ͠ʂ
TL;DR • cakephp/chronos A standalone DateTime library originally based off
of Carbon • Date(calendar) / DateTimeͷศརͳॲཧΛఏڙ ͢Δ • ࣌ॲཧΛҕৡ͢Δ͜ͱͰɺ γεςϜ࣌ʹґଘ͠ͳ͍ʮݱࡏ࣌ʯΛॲཧ͕ Մೳʹ
Α͋͘Γͦ͏ͳ
དྷ݄ɺզ͕ࣾ ͕ECαΠτʮଠ ܅ͷ͓หശʯ Λ࢝Ίͯɺ7प ͩɻ ײँͷؾ࣋ͪΛ ͜Ίͨɺεϖγϟ ϧηʔϧΛΖ ͏Α ࣾͷਓ
͕ࣾɺϫλ γʹͱͬͯ ΤϞ͍ࣄΛ ͤͯ͘Εͨ ͧɻ͜Εઈ ରʹࣦഊͰ͖ ͳ͍ɺ͕Μ Δ͔͠ͳ͍ʂ ৽ೖࣾһϫλγ
͋ʙΒΑͬʂͱɻ $template = 'itsumono_hanbai_page'; if (time() >= strtotime(START_SALE_DATETIME_STR)) { $template
= 'special_taro_sale'; } render($template);
͜ΕͰɺ ʹͳͬͨΒϖʔ δ͕ΓସΘ Δɻྑ͔ͬͨɺ ྑ͍ײ͡ʹ ࣄ͕Ͱ͖ͨͧɻ ৽ೖࣾһϫλγ
͊ɺ͕Μͬ ͨͶʂ͏Ұ ਓલ͍͔ۙ ͳʁ(স)͜Εͳ ΒɺΈΜ ͳେتͼʹҧ ͍ͳ͍ɻ͠ ͘ͳΔͧʙʙʂ པΕΔઌഐ
ͱ͜ΖͰ͞ʂ ͜Εͬͯɺ ͏CI௨ͨ͠ ͔ͳʁͲ͏ͩͬ ͨʁ པΕΔઌഐ
͋ɺઌഐʂς ετͬͯ͜ͱ Ͱ͔͢ʁϩʔ ΧϧͰɺγ εςϜλΠϜ Λมߋͯ͠ಈ ࡞֬ೝ͠· ͨ͠ɻ ৽ೖࣾһϫλγ
ͰɺΉΉΉɺ ͔֬ʹςετ ίʔυɾɾɾ runkitͱ͔ೖ ΕͪΌ͍ͬͯ ͍Ͱ͔͢Ͷʁ ৽ೖࣾһϫλγ
͏Μ͏Μɺͦ ͏ͩΑͶɻͦ Μͳ࣌ʹɺͱͬ ͯศརͳ Μͷ͕͋ΔΜ ͩɻ པΕΔઌഐ
cakephp/chronos͞ʂ
৭ʑͱػೳ͕ ͋ΔΑ པΕΔઌഐ
ԼͷΒͷ ؔ৺ͱͯ͠ɺ ʮtesting aidʯػೳ͕ ʹཱͪͦ͏ͩ ͔Βɺհ͢ ΔͶɻ པΕΔઌഐ
setTestNow()
before $template = 'itsumono_hanbai_page'; if (time() >= strtotime(START_SALE_DATETIME_STR)) { $template
= 'special_taro_sale'; } render($template);
·ͣɺʮݱࡏʯʹ͍ͭͯ ͯ͢Chronosܦ༝ͰऔΓग़͢Α͏ʹॻ͖͑ΔΑ use Cake\Chronos\Chronos; $template = 'itsumono_hanbai_page'; if (Chronos::now() >=
strtotime(START_SALE_DATETIME_STR)) { $template = 'special_taro_sale'; } render($template);
͍ͭͰʹɺ ૬खํॻ͖͑ͯ͠·͓͏ use Cake\Chronos\Chronos; $template = 'itsumono_hanbai_page'; if (Chronos::now() >=
new Chronos(START_SALE_DATETIME_STR) ) { $template = 'special_taro_sale'; } render($template);
ൺֱϝιουΛ͏ͱ ܕνΣοΫͰ͖ΔͷͰɺ͓ΈͰɻ use Cake\Chronos\Chronos; $template = 'itsumono_hanbai_page'; if (Chronos::now()->gte(new Chronos(START_SALE_DATETIME_STR))
) { $template = 'special_taro_sale'; } render($template);
ϓϩμΫτίʔ υͷ४උͰ ͖ͨɻͯ͞ɺ ͜ΕͰςετ ͕ॻ͚ΔΜͩ Αʂ པΕΔઌഐ
testίʔυΛॻ͍ͯΈΔ /** * @test */ public function セール開始前() { Chronos::setTestNow('2019-03-10');
$targetPageUrl = '/'; $actual = get($targetPageUrl); $this->assertTitleIs( '太郎君のお弁当箱', $actual ); }
testίʔυΛॻ͍ͯΈΔ /** * @test */ public function セール開始前() { Chronos::setTestNow('2019-03-10');
$targetPageUrl = '/'; $actual = get($targetPageUrl); $this->assertTitleIs( '太郎君のお弁当箱', $actual ); } ͜͜ʹೖΕ͕ͨ A$ISPOPTOPX AʹͳΔ
testίʔυΛॻ͍ͯΈΔ /** * @test */ public function セール期間中() { Chronos::setTestNow('2019-04-01');
$targetPageUrl = '/'; $actual = get($targetPageUrl); $this->assertTitleIs( '太郎君のお弁当箱〜7周年ありがとう!〜', $actual ); } ֘ظؒʹ͓͍ͯ ϖʔδίϯςϯπ͕ ࠩ͠ସΘΔ͜ͱΛظ͢Δ
testίʔυΛॻ͍ͯΈΔ /** * @test */ public function セール終了後() { Chronos::setTestNow('2019-05-01
06:59:59’); $targetPageUrl = '/'; $actual = get($targetPageUrl); $this->assertTitleIs( ‘太郎君のお弁当箱', $actual ); } ࣌ࠁϨϕϧ·ͰݻఆՄೳ
͓ͬͱɺऴྃ ࣌ͷઃఆΛͯ͠ ͳ͔͔ͬͨͶʂ ͪΖΜɺ͙͢ ʹඞཁͳ͍͚ Ͳɺࠓͷ͏ͪʹ ͓͍ͬͯͪΌ ͑҆৺ͩͶʂ པΕΔઌഐ
Θɺ͋Ϳͳ͍ʂ ઌഐ͋Γ͕ͱ ͏͍͟͝·͢ʂ ͬͺΓɺς ετ͕(͔͠ ؆୯ʹ)ॻ͚Δ ͱ҆৺ײ͕͋ Δͳʙ ৽ೖࣾһϫλγ
ͪͳΈʹɺ `setTestNow(null )` ͯ͋͛͠Εɺ ϑΣΠΫ࣌Ͱ ͳ͘ݱ࣮ͷ͕࣌ ฦͬͯ͘ΔͷͰ҆ ৺͞ɻςετͰ ͏࣌ͱ͔ɺ tearDown()ʹڬΜ
Ͱ͓͖͍ͨͶɻ པΕΔઌഐ
ଞʹศརͳ͜ͱ (࣌ؒ͋ΕͶ!)
৭ʑͱϔϧύʔͳͲ • DateTimeInterfaceDateTimeImmutableͷػೳͦͷ··͑Δͷ ͰɺҠߦͦΜͳʹ͠ΜͲ͘ͳ͍ͣ • add/sub/diffͳͲͳͲ • ࣌ૢ࡞ʹɺʮࣗવจͬΆ͍දݱͰಡΈ͍͢ʯAPI͕૿͑Δҹ • ge/gte/lt/lte/between/wasWithinLastͳͲͷൺֱػೳ
• addDays(int $value) / subMonths(int $value)ͳͲͷߋ৽ػೳ • Chronos::yesterday() / Chronos::instance(DatetimeInterface $dt) ͳͲͷϑΝΫτϦ
ΞάϨογϒͳ͍ํ <?php use Cake\Chronos\Chronos; if (!function_exists('now')) { function now() {
return Chronos::now(); } } // usage if (now()->isSunday()) { goto doNidone(); }
(ͪͳΈʹ)cakephpͷ߹ • I18nܥύοέʔδͰܧঝͨ͠ɺTime/FrozenTime ͕ར༻͞Ε͍ͯΔ • timezonelocaleͷใΛ͍࣋ͬͯΔ • https://github.com/cakephp/i18n/blob/master/ FrozenTime.php •
ORMܦ༝ͰRDBMS͔ΒऔΓग़ͨ͠datetimeྻͷ ɺࣗಈతʹίΠπʹϚʔγϟϧ͞ΕΔ
·ͱΊ
·ͱΊ(1/2) • ςετ = ҆৺ײ • ςελϒϧ = ઃܭͷɺςεςΟϯάϑϨʔ ϜϫʔΫ(etc)ଆͷදݱྗͷ
• ࣌Λࢧ͢Δͱͱͬͯศར ಛʹςετɺ͜ΕͰTDDΓ͍ͧ͢ʂ
·ͱΊ(2/2) • cakephpνʔϜͷϝϯς͚ͩͲɺελϯυΞ ϩϯͰ͑ΔͷͰɺͲ͜ʹͰ࿈Ε͍͚ͯΔʂ • ʮਂ0࣌ʙਂ2࣌ͷؒ௨Βͳ͍ʯ͔Βͷ ଔۀɾɾɾʂ
͓͖߹͍͍ ͖ͨͩ ͋Γ͕ͱ͏͝ ͍͟·ͨ͠ʂ