Share
Embed
PHPバージョンアップと決済リプレイスを支えたユニットテスト #phpcon
PHP Conference 2018での登壇資料です。
- なぜ我々はユニットテストが必要なのか
- 既存コードを保護する技法
- ユニットテスト量を増やす試み
- ユニットテスト増加における課題と対策
- テストがないコードを再生産しない技法
- まとめ
Kazuki Higashiguchi
December 13, 2018
Transcript
110 slides
-
About me • ౦ޱ ᏻ (@higasgt) • Server Side EngineerʢPHP
/ Goʣ • BASE, Inc. / BASE Product Division • PHPόʔδϣϯΞοϓ / ޙ͍ܾࡁϦϓϨΠε / YELL BANK • Blog: http://khigashigashi.hatenablog.com/ -
Agenda 1. ͳͥզʑϢχοτςετ͕ඞཁͳͷ͔ 2. طଘίʔυΛอޢ͢Δٕ๏ 3. ϢχοτςετྔΛ૿͢ࢼΈ 4. Ϣχοτςετ૿Ճʹ͓͚Δ՝ͱରࡦ 5.
ςετ͕ͳ͍ίʔυΛ࠶ੜ࢈͠ͳ͍ٕ๏ 6. ·ͱΊ -
อकɾ֦ுʹର͢Δཁٻ 1. طଘͷৼΔ͍Λม͑ͳ͍͜ͱ 2. طଘͷৼΔ͍Λมߋͯ͠ਖ਼͘͠ಈ͘͜ ͱ 3. ৽نͷৼΔ͍ΛՃͯ͠ਖ਼͘͠ಈ͘͜ ͱ
େ͖͘3छྨͷཁٻͱͱʹʑͷ։ൃΛ͠ ͍ͯΔɻ -
- อकɾ֦ுʹର͢Δཁٻɿࣄྫ - 1. طଘͷৼΔ͍Λม͑ͳ͍ • ʮPHPɾCakePHPόʔδϣϯΞοϓʯ • 2016͔Β࢝·ͬͨPHPɾCakePHPͷ όʔδϣϯΞοϓσʔτ
• PHP5.3 -> PHP7.1 • CakePHP2.3~2.10 -> CakePHP2.10(2.x ࠷৽) • 20185݄ʹྃ -
• 60ສళฮͷγϣοϓ͕ར༻͍ͯ͠ΔαʔϏ εͷݴޠɾϑϨʔϜϫʔΫͷόʔδϣϯΞο ϓ • ίʔυϕʔεશମʹର͢ΔӨڹൣғ • PHPɾCakePHPͷόʔδϣϯΛ҆શʹ্͛ Δඞཁੑ
- อकɾ֦ுʹର͢Δཁٻɿ1. طଘͷৼΔ͍Λม͑ͳ͍ - PHP/CakePHPόʔδϣϯΞοϓ -
• ʮޙ͍ܾࡁϦϓϨΠεʯ • BASEओʹҎԼ5ͭͷܾࡁํ๏ΛରԠ • ΫϨδοτΧʔυܾࡁɺίϯϏχܾࡁɾPay-easyɺۜ ߦৼࠐɺޙ͍ܾࡁɺΩϟϦΞܾࡁ • ʮޙ͍ܾࡁʯͷϦϓϨΠεΛ࣮ࢪɻ IUUQTCBTFVKQ
- อकɾ֦ுʹର͢Δཁٻɿࣄྫ - 2. طଘͷৼΔ͍Λมߋ͢Δ -
• Ϣʔβʔͷ͓͕ۚؔΘΔͷͰɺԿࣄͳ͘ ҆શʹ͢Δඞཁੑ • طଘίʔυͷৼΔ͍Λཧղ্ͨ͢͠Ͱख ΛೖΕΔ͜ͱ͕ٻΊΒΕΔɻ • طଘͷৼΔ͍Λอޢ্ͨ͠ͰɺϦϑΝΫ λϦϯάɾৼΔ͍ՃΛߦ͍͍ͨɻ
- ޙ͍ܾࡁϦϓϨΠε - ςετʹΑ࣮ͬͯݱ͍ͨ͜͠ͱ -
• ओͱͳΔػೳWeb APIͰ࣮ɺBASEຊ ମͷίʔυϕʔε͔ΒΞΫηε • ʮϨΨγʔίʔυʯͱͳΒͳ͍อकੑͷ͋ ΔίʔυΛॻ͖͍ͨɻ • ૄ݁߹ͳίʔυઃܭΛਪਐ͠ɺৼΔ͍อ ޢΛଅਐ͢Δ
- อकɾ֦ுʹର͢Δཁٻɿ৽نͷৼΔ͍ΛՃ͢Δ - YELL BANKʢΤʔϧόϯΫʣ -
ڞ௨తͳϞνϕʔγϣϯ • ςετΛॻ͘͜ͱʹΑͬͯɺΑΓ҆શʹγ εςϜΛѻ͍͍ͨϞνϕʔγϣϯ • ฤूͯ͠فΔʢEdit and Prayʣ • อޢͯ͠มߋ͢ΔʢCover
and Modifyʣ • ૄ݁߹ͳίʔυઃܭʹ͠ɺ৽نʹϨΨγʔ ίʔυΛ࢈·ͳ͍ -
- طଘίʔυΛอޢ͢Δٕ๏ - 1. ༷Խςετ • “characterization test” • ίʔυͷطଘͷৼΔ͍Λ໌Β͔ʹ͢Δς
ετ • ॲཧͰૢ࡞͢Δཁૉʹର͢Δ࣮ࢪ͍ͯ͠ ͘ • Viewʹηοτ͞ΕΔ • Sessionͷ • Dataͷొ/ߋ৽ • FUD -
• “exploratory refactoring” • طଘίʔυʹର͢ΔཧղΛਂΊΔ • “ʮະͷڪΕʯΛࠀ͢Δ࠷ྑͷํ๏ɺͦͷ ίʔυʹඈͼࠐΜͰɺ͍͡Γ࢝ΊΔ͜ͱͩɻ” (ʰϨΨ γʔιϑτΣΞվળΨΠυʱ)
• ཧղΛਂΊΔͨΊิॿͱͯ͠ʮ༷Խςε τʯΛߦ͏ https://www.shoeisha.co.jp/book/detail/9784798145143 - طଘίʔυΛอޢ͢Δٕ๏ɿ1. ༷Խςετ - ௐࠪతϦϑΝΫλϦϯά -
1. ςετίʔυͷதͰରͷίʔυΛݺͼ ग़͢ 2. ࣦഊ͢ΔͱΘ͔͍ͬͯΔද໌Λॻ͘ 3. ࣦഊͨ݁͠Ռ͔Β࣮ࡍͷৼΔ͍Λ֬ೝ ͢Δ 4. ίʔυ͕࣮ݱ͢ΔৼΔ͍Λظ͢ΔΑ
͏ʹɺςετΛมߋ͢Δ 5. Ҏ্ͷखॱΛ܁Γฦ͢ - طଘίʔυΛอޢ͢Δٕ๏ɿ1. ༷Խςετ - ༷Խςετͷखॱ -
- 1. ༷Խςετɿ༷Խςετͷखॱ - 1. ςετίʔυͷதͰରͷίʔυΛ ݺͼग़͢ $result = $this->testAction(
‘/samples/index’, [‘data’ => $data, ‘method’ => ‘post’] ); 1. ςετίʔυͷதͰରͷίʔυΛݺͼग़͢ -
$result = $this->testAction( ‘/samples/index’, [‘data’ => $data, ‘method’ => ‘post’]
); $expected = []; $this->assertSame($expected, $this->vars); 2. ࣦഊ͢ΔͱΘ͔͍ͬͯΔද໌Λॻ͘ - 1. ༷Խςετɿ༷Խςετͷखॱ - 2. ࣦഊ͢ΔͱΘ͔͍ͬͯΔද໌Λॻ͘ -
$ ./Console/cake test app —-stderr Controller/SampleController PHPUnit 5.7.27 by Sebastian
Bergmann and contributors. F 1 / 1 (100%) Time: 19.32 seconds, Memory: 16.00MB There was 1 failure: --- Expected +++ Actual @@ @@ -Array &0 () +Array &0 ( ‘result’ => [‘success’] ) 3. ࣦഊͨ݁͠Ռ͔Β࣮ࡍͷৼΔ͍Λ֬ೝ͢Δ - 1. ༷Խςετɿ༷Խςετͷखॱ - 3. ࣦഊͨ݁͠Ռ͔Β࣮ࡍͷৼΔ͍Λ ֬ೝ͢Δ -
$result = $this->testAction( ‘/samples/index’, [‘data’ => $data, ‘method’ => ‘post’]
); $expected = [ ‘result’ => [‘success’] ]; $this->assertSame($expected, $this->vars); 4. ίʔυ͕࣮ݱ͢ΔৼΔ͍Λظ͢ΔΑ͏ ʹɺςετΛมߋ͢Δ 5. Ҏ্ͷखॱΛ܁Γฦ͢ - 1. ༷Խςετɿ༷Խςετͷखॱ - 4. ίʔυ͕࣮ݱ͢ΔৼΔ͍Λظ͢ ΔΑ͏ʹɺςετΛมߋ͢Δ -
• طଘίʔυͷৼΔ͍Λྫ֎ܥؚΊͯอূ ͢Δࣄ͕Մೳ • ςετΛॻ͘͜ͱͰݱࡏͷ࣮༷Λཧղ ͢Δ͜ͱ͕Ͱ͖Δ • ҆શͳϦϑΝΫλϦϯάʹͭͳ͕Δ -
طଘίʔυΛอޢ͢Δٕ๏ɿ1. ༷Խςετ - ༷Խςετͷޮ༻ -
1. ༷ԽςετΛॻ͘ 2. ςετ͕௨Δ͜ͱΛ֬ೝ͢Δ 3. ϦϑΝΫλϦϯά͢Δ 4. ςετ͕௨Δ͜ͱΛ֬ೝ͢Δ -
طଘίʔυΛอޢ͢Δٕ๏ɿ1. ༷Խςετ - ҆શͳϦϑΝΫλϦϯάͷखॱ -
- ҆શͳϦϑΝΫλϦϯάɿྫ - ରϝιου /** * ར༻Մೳ͔Ͳ͏͔Λఆ͢Δ * @param int|null
$user_id * @return bool */ public function canUse(int $user_id = null): bool { if (!is_null($user_id)) { $user = $this->User->find('first', [ 'conditions' => ['user_id' => $user_id] ] ); if (empty($user)) { return false; } $available = $user['User']['available']; return $available; } else { return false; } } ૣظreturn͢ΔίʔυʹϦϑΝΫλϦϯά͍ͨ͠߹ -
/** * @dataProvider dataProvider_canUse * @param int|null $user_id * @param
bool $expected */ public function test_canUse(?int $user_id, bool $expected): void { $this->assertSame($expected, $this->User->canUse($user_id)); } public function dataProvider_canUse(): array { return [ 'user_id͕null' => [null, false], 'ଘࡏ͢Δuser_idͰར༻Մೳ' => [1, true], 'ଘࡏ͢Δuser_idͰར༻ෆՄ' => [2, false], ]; } ϦϑΝΫλϦϯάରϝιουʹର͢ΔςετΛॻ͘ - ҆શͳϦϑΝΫλϦϯάɿྫ - 1. ༷ԽςετΛॻ͘ -
/** * @dataProvider dataProvider_canUse * @param int|null $user_id * @param
bool $expected */ public function test_canUse(?int $user_id, bool $expected): void { $this->assertSame($expected, $this->User->canUse($user_id)); } public function dataProvider_canUse(): array { return [ 'user_id͕null' => [null, false], 'ଘࡏ͢Δuser_idͰར༻Մೳ' => [1, true], 'ଘࡏ͢Δuser_idͰར༻ෆՄ' => [2, false], ]; } PHPUnitͷdataProviderΛར༻͢Δ͜ͱͰςετέʔεΛγϯϓϧʹ - ҆શͳϦϑΝΫλϦϯάɿྫ - 1. ༷ԽςετΛॻ͘ -
-> % ./app/Console/cake test app User --filter test_canUse PHPUnit 5.7.27
by Sebastian Bergmann and contributors. ... 3 / 3 (100%) Time: 5.9 seconds, Memory: 14.00MB OK (3 tests, 3 assertions) - ҆શͳϦϑΝΫλϦϯάɿྫ - 2. ςετ͕௨Δ͜ͱΛ֬ೝ͢Δ -
- ҆શͳϦϑΝΫλϦϯάɿྫ - 3. ϦϑΝΫλϦϯά͢Δ /** * ར༻Մೳ͔Ͳ͏͔Λఆ͢Δ * @param
int|null $user_id * @return bool */ public function canUse(int $user_id = null): bool { if (is_null($user_id)) { return false; } $user = $this->User->find('first', [ 'conditions' => ['user_id' => $user_id] ] ); if (empty($user)) { return false; } $available = $user['User']['available']; return $available; } ૣظreturn͢ΔίʔυʹϦϑΝΫλϦϯά -
-> % ./app/Console/cake test app User --filter test_canUse PHPUnit 5.7.27
by Sebastian Bergmann and contributors. ... 3 / 3 (100%) Time: 5.9 seconds, Memory: 14.00MB OK (3 tests, 3 assertions) - ҆શͳϦϑΝΫλϦϯάɿྫ - 4. ςετ͕௨Δ͜ͱΛ֬ೝ͢Δ -
• ςετΛॻͨ͘ΊʹɺίʔυΛมߋ͢Δඞ ཁ͕͋Δέʔε͕͋Δ • ͍ΘΏΔɺςετ͠ʹ͍͘ίʔυʹରࡦ͕ ඞཁ - طଘίʔυΛอޢ͢Δٕ๏ -
2. ϨΨγʔίʔυͷδϨϯϚͱͷ֨ಆ -
• ςετ͕ͳ͍ίʔυɺςετ͠ʹ͍͘ ίʔυͰ͋Δ͜ͱ͕ଟ͍ • ֎෦ଓΛؚΉ࣮ͱͷີ݁߹ • ܾࡁγεςϜɾAWS • ͷେ͖͍ϝιου
- طଘίʔυΛอޢ͢Δٕ๏ɿ2. ϨΨγʔίʔυ - ςετ͠ʹ͍͘ίʔυ -
• ςετ͕͔͚ΔΑ͏ʹॻ͖͑Δ • ີ݁߹ΛMockΛࠩ͠ࠐΊΔஈ֊·Ͱղফ ͢Δ • ςετ࣌ʹMockΛࠩ͠ࠐΉ • ֎෦࿈ܞͷৼΔ͍ͷMockΫϥεΛ࡞ •
֎෦࿈ܞͳͲΛؚΉςετΛߦ͏ࡍɺ֘ ΫϥεΛMockʹஔ͖͑Δ - طଘίʔυΛอޢ͢Δٕ๏ɿ2. ϨΨγʔίʔυ - ςετ͠ʹ͍͘ίʔυͷରࡦ -
• σβΠϯύλʔϯͷҰͭ • ֎෦͔Βґଘؔͷ͋ΔΦϒδΣΫτΛ ೖ͢Δ • ;Δ·͍ͱґଘੑղܾΛ • https://github.com/google/guice/wiki/Motivation •
Martin FowlerࢯʹΑΓఏএ͞Εͨ༻ޠ • https://www.martinfowler.com/articles/injection.html - طଘίʔυΛอޢ͢Δٕ๏ɿ2. ϨΨγʔίʔυ - Dependency Injection -
େ͖͘3ͭͷDIͷΓํ • Constructor Injection • Setter Injection • Interface Injection
- Dependency Injection - DI Pattern IUUQTXXXNBSUJOGPXMFSDPNBSUJDMFTJOKFDUJPOIUNM -
// Before public function charge($order) { $manager = new PaymentManager();
$result = $manager->charge($order); // ܾࡁγεςϜʹ௨ } PaymentManagerͱີ݁߹ɺ Mockͷࠩ͠ସ͕͍͑͠ - ςετ͠ʹ͍͘ίʔυɿྫ - खಈDIͰີ݁߹Λղফ͢Δ -
// After public function __construct($PaymentManager = null) { $this->manager =
$PaymentManager ?? new PaymentManager(); } public function charge($order) { $result = $this->manager->charge($order); // ܾࡁγεςϜʹ௨ } Constructor Injection ίϯετϥΫλͷҾͰ͢͜ͱͰɺ Mockͷࠩ͠ସ͑Λ༰қʹ͢Δ - ςετ͠ʹ͍͘ίʔυɿྫ - खಈDIͰີ݁߹Λղফ͢Δ -
// mock objectΛ࡞Δ $mock = $this->getMockBuilder(Sample::class) ->setMethods(['update']) ->getMock(); // mock
objectͷϝιουͷظͱฦ͢Λఆٛ $mock->expects($this->once()) ->method('update') ->with($this->equalTo(‘param1')) ->will($this->returnValue(true); // Constructor injection͢Δ߹ $target = new Target($mock); IUUQTQIQVOJUEFNBOVBMFOUFTUEPVCMFTIUNM - ςετ͠ʹ͍͘ίʔυɿྫ - खಈDIͰີ݁߹Λղফ͢Δ -
// mock objectΛ࡞Δ $mock = $this->getMockBuilder(Sample::class) ->setMethods(['update']) ->getMock(); // mock
objectͷϝιουͷظͱฦ͢Λఆٛ $mock->expects($this->once()) ->method('update') ->with($this->equalTo(‘param1')) ->will($this->returnValue(true); // Constructor injection͢Δ߹ $target = new Target($mock); MockΦϒδΣΫτΛ࡞͢Δ (PHPUnit Test Doubles) https://phpunit.de/manual/6.5/en/test-doubles.html - ςετ͠ʹ͍͘ίʔυɿྫ - खಈDIͰີ݁߹Λղফ͢Δ -
// mock objectΛ࡞Δ $mock = $this->getMockBuilder(Sample::class) ->setMethods(['update']) ->getMock(); // mock
objectͷϝιουͷظͱฦ͢Λఆٛ $mock->expects($this->once()) ->method('update') ->with($this->equalTo(‘param1')) ->will($this->returnValue(true); // Constructor injection͢Δ߹ $target = new Target($mock); - ςετ͠ʹ͍͘ίʔυɿྫ - खಈDIͰີ݁߹Λղফ͢Δ Constructor InjectionΛߦ͏ -
• ςετ͠ʹ͍͘ίʔυͷղফʹ͕͔͔࣌ؒ Δ߹ • ີ݁߹Λղ͘ͷʹେ͖ͳϦϑΝΫλϦϯάΛཁ͢Δ • ґଘ͍ͯ͠ΔΫϥεͷதͰɺ࣮ࡍʹ֎෦௨৴Λߦ͏ίʔ υΛؚΉͱ͍ͬͨ߹ • ςετ͠ʹ͍͘Օॴʹରͯ͠ɺͲ͏खΛೖ
ΕΔ͔ • runkitΛ׆༻ͯ͠ςετΛॻ͘ - طଘίʔυΛอޢ͢Δٕ๏ɿ2. ϨΨγʔίʔυ - ςετ͠ʹ͍͘ίʔυͷน -
• runkit֦ுϞδϡʔϧ • ఆɾϢʔβʔఆٛؔ ͓ΑͼϢʔβʔఆ ٛΫϥεΛมߋ͢ΔػೳΛఏڙ • ΈࠐΈؔͷڍಈΛมߋ͍ͨ͠߹ͳͲ ʹར༻Ͱ͖Δ
IUUQQIQOFUNBOVBMKBJOUSPSVOLJUQIQ - ςετ͠ʹ͍͘ίʔυͷน - runkit -
// ରؔఆٛΛॻ͖͑Δ $val = <<<_XML__ <response>success</response> __XML__; runkit_function_copy(‘curl_exec’, ‘curl_exec_org’); runkit_function_redefine(‘curl_exec’,
‘’, $val); // ςετରίʔυΛ࣮ߦ $result = $this->Sample->exec(); // ॻ͖͑ͨؔఆٛΛͱʹ͢ runkit_function_remove(‘curl_exec’); runkit_function_copy(‘curl_exec_org’, ‘curl_exec’); runkit_function_remove(‘curl_exec_org’); ؔఆٛͷόοΫΞοϓΛऔΓɺظ͢ΔϨεϙ ϯε($val)Λฦ͢Α͏ʹ࠶ఆٛ͢Δ - ςετ͠ʹ͍͘ίʔυͷน - runkitΛ༻͍ͨςετ -
// ରؔఆٛΛॻ͖͑Δ $val = <<<_XML__ <response>success</response> __XML__; runkit_function_copy(‘curl_exec’, ‘curl_exec_org’); runkit_function_redefine(‘curl_exec’,
‘’, $val); // ςετରίʔυΛ࣮ߦ $result = $this->Sample->exec(); // ॻ͖͑ͨؔఆٛΛͱʹ͢ runkit_function_remove(‘curl_exec’); runkit_function_copy(‘curl_exec_org’, ‘curl_exec’); runkit_function_remove(‘curl_exec_org’); ςετରίʔυΛ࣮ߦ - ςετ͠ʹ͍͘ίʔυͷน - runkitΛ༻͍ͨςετ -
// ରؔఆٛΛॻ͖͑Δ $val = <<<_XML__ <response>success</response> __XML__; runkit_function_copy(‘curl_exec’, ‘curl_exec_org’); runkit_function_redefine(‘curl_exec’,
‘’, $val); // ςετରίʔυΛ࣮ߦ $result = $this->Sample->exec(); // ॻ͖͑ͨؔఆٛΛͱʹ͢ runkit_function_remove(‘curl_exec’); runkit_function_copy(‘curl_exec_org’, ‘curl_exec’); runkit_function_remove(‘curl_exec_org’); όοΫΞοϓΛऔ͍ͬͯͨͱͱͷؔఆٛʹ ࠶ఆٛ͢͠ - ςετ͠ʹ͍͘ίʔυͷน - runkitΛ༻͍ͨςετ -
• Θͳ͍ʹӽͨ͜͠ͱͳ͍ • ৽ن࣮ͷςετίʔυɺrunkitར༻Λ લఏͱ͠ͳ͍Α͏ʹप্ͨ͠Ͱ༻͢Δ • PHPͷόʔδϣϯʹԠͯ͡ɺʮpeclͰͷ ͳͷ͔ʯར༻ํ๏͕ҟͳΔ • https://qiita.com/kunit/items/
43ca86a461d2e5e051cf - ςετ͠ʹ͍͘ίʔυͷน - runkitར༻ͷҙ -
ςετΛॻ͖͍͢Έ • αʔϏεڞ༻ͷςετεΠʔτϓϥάΠϯ • ϑΟΫενϟػߏΛ֦ு • άϩʔόϧมཧ • PHPUnit7.xܥػೳͷόοΫϙʔτ •
ʮassertSameͷdiff͕ݟ͘͢͢ΔʯͳͲ -
• ςετέʔεͷ͕૿͑Δʹ࿈Εͯɺʮ৮ͬ ͍ͯͳ͍Օॴͷςετ͕མͪΔʯέʔεͷ૿ Ճɻ • ʮϩʔΧϧͰ௨Δ͕ɺCIڥͰམͪ Δʯͱ͍͏έʔεൃੜ͢Δ • ମݧͱͯ͠ɺʮςετ͕োʯʹͳΔ
- Ϣχοτςετ૿Ճʹ͓͚Δ՝ͱରࡦ - ՝ɿഁ͍͢͠ςετ -
- ഁ͍͢͠ςετྫ - ֎෦ཁҼͷมԽʹӨڹ͞ΕΔςετ // test༻CloudSearchʹଓ͢Δ $search = CloudSearchWrapper::factory(); $search->conditions()
->keyword(‘test’, ‘title’) ->sort(‘list_order asc’); // test༻CloudSearchʹσʔλొ $search->documentBatch($this->addJson()); // σʔλొ͞ΕΔ·Ͱ͙͢ʹݕࡧͰ͖ͳ͍ͷͰɺͭ sleep(3); // ݕࡧ࣮ߦ $result = $search->search($search->conditions()->query()); ωοτϫʔΫঢ়گʹґଘͯ͠མͪΔ -
$data = [‘name’ => ‘hogehoge’]; $result = $this->Sample->saveSample($data); $expected =
[ ‘id’ => 1, ‘name’ => ‘hogehoge’, ]; $data = ClassRegistry::init(‘Sample’)->find(‘first’, [ ‘conditions’ => [‘name’ => ‘hogehoge’] ]; $this->assertSame($expected, $data); Sample modelʹରԠ͢ΔϑΟΫενϟʹɺ ϨίʔυΛೖΕΔͱɺ ɹsave࣌ͷid͕auto increment͞ΕམͪΔ - ഁ͍͢͠ςετྫ - FixtureͷมԽʹහײʹམͪΔςετ -
- ςετεΠʔτ֦ுʹΑΔԉॿɿྫ - CakePHP2Ͱͷ֦ுྫʢ1ʣ class UserTest extends AppTestCase { public
$fixtures = [ 'app.user', ]; public $autoFixtures = false; public function test_canUser_ར༻ՄೳϢʔβʔ(): void { $this->loadFixturesWithRecords([ 'User' => [ UserTestHelper::availableUser, ], ]); $this->assertTrue($this->User->canUse(1)); } } -
- ςετεΠʔτ֦ுʹΑΔԉॿɿྫ - CakePHP2Ͱͷ֦ுྫʢ1ʣ class UserTest extends AppTestCase { public
$fixtures = [ 'app.user', ]; public $autoFixtures = false; public function test_canUser_ར༻ՄೳϢʔβʔ(): void { $this->loadFixturesWithRecords([ 'User' => [ UserTestHelper::availableUser, ], ]); $this->assertTrue($this->User->canUse(1)); } } CakePHPͷCakeTestCaseΛ֦ுɻ ඞཁͳςʔϒϧɾϨίʔυΛςετέʔεͰload͢Δ -
- ςετεΠʔτ֦ுʹΑΔԉॿɿྫ - CakePHP2Ͱͷ֦ுྫʢ1ʣ <?php class UserTestHelper { const availableUser
= [ 'id' => 1, 'name' => 'hogehuga', 'available' => 1, 'created' => '2018-12-15 15:30:00', 'modified' => '2018-12-15 15:30:00', ]; } ςετέʔε͝ͱʹඞཁͳϨίʔυঢ়ଶΛఆٛ -
- ςετεΠʔτ֦ுʹΑΔԉॿɿྫ - CakePHP2Ͱͷ֦ுྫʢ2ʣ class UserTest extends AppTestCase { public
$fixtures = [ 'app.user', ]; public $autoFixtures = false; public function test_canUser_ར༻ՄೳϢʔβʔ(): void { $this->loadFixturesWithRecords([ 'User' => ‘User/User.php’, ]); $this->assertTrue($this->User->canUse(1)); } } ϑΝΠϧͰςετέʔεʹඞཁͳϨίʔυΛࢦఆ͢Δ -
- ςετεΠʔτ֦ுʹΑΔԉॿɿྫ - CakePHP2Ͱͷ֦ுྫʢ2ʣ <?php return [ [ 'id' =>
1, 'available' => 1, ] ]; ςετέʔεʹͱͬͯ໌ࣔతʹඞཁͳΧϥϜͷΈΛࢦఆ͢Δɻ ࢦఆ͍ͯ͠ͳ͍ΧϥϜɺςετ࣮ߦ࣌ʹfzaninotto/Fakerʹ ΑΓμϛʔͷΛࣗಈઃఆ IUUQTHJUIVCDPNG[BOJOPUUP'BLFS -
• શςετέʔεڞ௨తͰͳ͍͕ɺ֘ςε τέʔεͰඞཁͳϨίʔυͷࢦఆ͕༰қ ͱͳͬͨ • ύζϧతͳϑΟΫενϟͷෳࡶԽΛճආͰ ͖Δ - ରࡦɿഁ͠ʹ͍͘ςετ
- ςετέʔε͝ͱͷFixtureͷར -
• ࠓճͷ༷ԽςετͰɺʮطଘͷৼΔ͍ʯΛൣғ Ͱอޢͨ͠ • ͍͕Ώ͑ʹɺςετ͕ରΫϥε͔Βԕ͍ॴ͕ݪҼ Ͱམͪͨࡍɺಛఆ͕͍͠ • “ςετ͕ςετର͔ΒΕΕΕΔ΄Ͳɺςετͷࣦഊ͕ԿΛҙ ຯ͢Δ͔ͷஅ͕͘͠ͳΓ·͢ɻ“ʢʰϨΨγʔίʔυվળΨΠ υʱʣ
• ςετϝϯςφϯεରͱͯ͠खΛೖΕଓ͚Δඞཁੑ - Ϣχοτςετ૿Ճʹ͓͚Δ՝ͱରࡦ - ՝ɿςετίʔυͷϦϑΝΫλϦϯά -
• ֤ࣗɺ༻ࣄ͕͋ͬͯमਖ਼͢ΔՕॴʹ͍ͭͯ ͜·ΊͳϦϑΝΫλϦϯάΛ͍ͯ͘͠ • PHPUnitͷػೳΛ༗ޮʹ͏ • લॲཧɾޙॲཧͷෆͷՃ • ݟ௨͠Λ্͛ΔͨΊͷςετϔϧύʔԽ •
ෆཁͳςετέʔεͷআ - ՝ɿςετίʔυͷϦϑΝΫλϦϯά - ରࡦɿςετίʔυͷϦϑΝΫλϦϯά -
- ςετ͕ͳ͍ίʔυΛ࠶ੜ࢈͞ΕΔཧ༝ - ςετΛॻ͘ͷ͕ਏ͍ࣄྫ • طଘॲཧʹΛՃͯ͠͠·͏ • طଘΫϥεͷprivateϝιουՃ • ֎෦ཁૉʹରͯ͠ີ݁߹
• ֎෦APIɾϝʔϧɾSlack ..etc • ͷେ͖͍Ϋϥεɾϝιου • ҰͭͷϝιουʹॲཧΛ٧ΊࠐΜͰ͠·͏ -
• ιϑτΣΞ։ൃʹؔ͢ΔจԽతͳنൣͱ ֶతΞϓϩʔνͷ·ͱ·ΓͷҰͭ • ಛʹೋͭͷΞϓϩʔνΛҙࣝ 1. “ͻͱͭͷ͜ͱΛ͏·͘Ε” 2. “Ͱ͖ΔݶΓૣ͘ݪܕʢϓϩτλΠϓʣ Λ࡞Εɻ”
- ςετ͕ͳ͍ίʔυΛ࠶ੜ࢈͠ͳ͍ٕ๏ - 1. UNIXֶ͔ΒֶͿ -
- ʮςετ͕ॻ͖͍͢ʯίʔυઃܭɿ1. UNIXֶ͔ΒֶͿ - 1. “ͻͱͭͷ͜ͱΛ͏·͘Ε” • Ұͭͷ͜ͱʹूத͢Δ͜ͱͰෆཁͳ෦Λ ແ͍ͯ͘͘͠ɻ
• ͕খ͍͞୯Ұ෦Λڠௐͯ͠ಈ͔͢ -
– ϚΠΫɾΨϯΧʔζɺUNIXֶ “Build a prototype as soon as possible.” ʢͰ͖ΔݶΓૣ͘ݪܕʢϓϩτλΠϓʣΛ࡞Εɻʣ
IUUQTKBXJLJQFEJBPSHXJLJ6/*9&#&"%" -
- ʮςετ͕ॻ͖͍͢ʯίʔυઃܭɿUNIXֶ͔ΒֶͿ - 2. “Ͱ͖ΔݶΓૣ͘ݪܕʢϓϩτλΠϓʣΛ࡞Ε” • ૣ͘࠷ݶͷظ͕ಘΒΕΔͨॻ͖ͷ ࣮Λߦ͏ •
࣮ମݧ͔Βઃܭʹର͢ΔϑΟʔυόοΫ Λಘͯվળ͍ͯ͘͠ • →ʮςετۦಈ։ൃʯ -
• “Test-Driven Development: TDD” • ࣗಈԽ͞ΕͨςετʹΑͬͯ։ൃΛਪ͠ਐΊ Δ • Kent Beck
ஶʰςετۦಈ։ൃʱ • https://shop.ohmsha.co.jp/shopdetail/000000004967/ - ςετ͕ͳ͍ίʔυΛ࠶ੜ࢈͠ͳ͍ٕ๏ - 2. ςετۦಈ։ൃ -
1. ·ͣςετΛ̍ͭॻ͘ 2. ͯ͢ͷςετΛΒͤɺ৽͍͠ςετͷ ࣦഊΛ֬ೝ͢Δ 3. খ͞ͳมߋΛߦ͏ 4. ͯ͢ͷςετΛΒͤɺશͯޭ͢Δ͜ ͱΛ֬ೝ͢Δ
5. ϦϑΝΫλϦϯάΛߦͬͯॏෳΛআڈ͢Δ - ςετۦಈ։ൃ - ςετۦಈ։ൃͷϦζϜ IUUQTTIPQPINTIBDPKQTIPQEFUBJM