12. 依存関係
? Bが無いとAを作れない
? CとDが無いとBを作れない
? どのように単体テストを行う
か
class A {
function __construct(B $b) {
}
}
class B {
function __construct(C $c, D $d) {
}
}
class C {
}
class D {
}
13. class B {
function __construct(C $c, D $d) {
}
}
class C {
}
class D {
}
class A {
function __construct(B $b) {
}
}
Outside-In/Inside-Out
? Outside-In
? Bをダミー(Mock, Stub)に置き換
えてAをテストする
? AがBに要求しているものが明確に
なる
? Inside-Out
? C,Dを先に実装してからBを実装す
る
? テストの粒度は次第に大きくなる
? ダミーを実装する手間はかからな
い
? Bを実装中はAが存在しないので、
AがBに何を要求するかわからない
16. class Markdown {
public function outputHtml($markdown, $writer) {
// $writer->writeText(
// MarkdownをHTMLに変換したもの
// );
}
}
class Writer {
public function writeText($text) {
// 何かする
}
}
src/Markdown.php
src/Writer.php
17. <?php
class MarkdownTest extends PHPUnit_Framework_TestCase
{
/** @test */
public function 変換したhtmlを出力できること()
{
$writer = ???;
// $writer->writeText('<p>Hi, there</p>') が
// 呼ばれること
$markdown = new Markdown();
$markdown->outputHtml('Hi, there', $writer);
}
}
tests/MarkdownTest.php
まず試し書き
18. <?php
class MarkdownTest extends PHPUnit_Framework_TestCase
{
/** @test */
public function 変換したhtmlを出力できること()
{
$writer = ???;
// $writer->writeText('<p>Hi, there</p>') が
// 呼ばれること
$markdown = new Markdown();
$markdown->outputHtml('Hi, there', $writer);
}
}
tests/MarkdownTest.php
19. class FakeWriter {
public function writeText($text) {
$this->text = $text;
}
}
Mocking Frameworkを使わずに書く
引数に何が渡されたかを後で調べるために保存
しておく
20. $writer = new FakeWriter();
$markdown = new Markdown();
$markdown->outputHtml('Hi, there',$writer);
$this->assertEquals(
'<p>Hi, there</p>'
$writer->text
);
tests/MarkdownTest.php
これはこれで場合によっては十分有効
27. $ vendor/bin/phpunit tests/MarkdownTest.php
F 1 / 1 (100%)
Time: 85 ms, Memory: 4.00Mb
There was 1 failure:
1) MarkdownTest::test_変換したhtmlを出力できること
Some predictions failed:
Double?Writer?P1:
No calls have been made that match:
Double?Writer?P1->writeText(exact("<p>Hi, there</p>"))
but expected at least one.
FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
28. <?php
class Markdown {
public function outputHtml($markdown, Writer $writer) {
$writer->writeText(
'<p>'.htmlspecialchars($markdown).'</p>'
);
}
}
src/Markdown.php
32. There was 1 error:
1) MarkdownTest::test_変換したhtmlを出力できること
Prophecy?Exception?Doubler?MethodNotFoundException:
Method `Double?stdClass?P1::writeText()` is not defined.
There was 1 error:
1) MarkdownTest::test_変換したhtmlを出力できること
Prophecy?Exception?Doubler?MethodNotFoundException:
Method `Double?Writer?P1::writeText()` is not defined.
Writerクラスが無い場合
writeTextメソッドが無い場合
35. さいごに
? 少しずつ前に進む
? 小さな部品を組み合わせて大きなプログラムを作る
? そのための手段としてのMockとユニットテスト
? 何故なら、プログラミングは未知との遭遇の連続だから
? あと、興味を持った方は ”Design How Your Objects Talk Through
Mocking at Laracon EU 2014 ” をCheck
36. 参考資料
? GitHub - phpspec/prophecy: Highly opinionated mocking framework
for PHP 5.3+
https://github.com/phpspec/prophecy
? thePHP.cc - PHPUnit 4.5 and Prophecy
https://thephp.cc/news/2015/02/phpunit-4-5-and-prophecy
? Design how your objects talk through mocking at Laracon EU 2014
? http://www.slideshare.net/everzet/design-how-your-objects-talk-through-
mocking
? https://www.youtube.com/watch?v=X6y-OyMPqfw
? Design How Your Objects Talk Through Mocking"を見た - iakioの日
記
http://iakio.hatenablog.com/entry/2014/10/06/000000