2015-01-31 90 views
2

我正在學習TDD,並且我有一些問題。 - 這個想法是創建一個由測試引導的簡單工廠。問題是我的測試覆蓋率不是100%,這是我的問題所在。PHPUnit TDD問題

在我告訴你代碼之前,讓我解釋一下我想要的。

  • 本廠是RESPONSABLE實例化類和測試這個我有模擬類的實例,這樣做我用一個具體的類,它的工作原理,但是當我看到測試覆蓋,具體類出現,並沒有100%測試。 (你會明白的)。 - 我想避免這種情況,我想盡可能抽象地測試工廠。
  • 而另一個問題是,我想插入工廠作爲依賴關係的構造函數,如何測試這個?

覆蓋率:

  • PizzaStore.php - 33,33% - 與工廠的依賴構造沒有進行測試。
  • PizzaFactory.php - 100%
  • Pizza.php - 100%
  • 披薩/ Greek.php - 0.00% - 使用混凝土類檢驗出廠後出現了。

yoda

PizzaTest.php:

<?php namespace Pattern\SimpleFactory; 

use PHPUnit_Framework_TestCase; 

class PizzaTest extends PHPUnit_Framework_TestCase { 

    private $pizza; 

    public function setUp() 
    { 
    $this->pizza = $this->getMockForAbstractClass('Pattern\SimpleFactory\Pizza'); 
    } 

    /** 
    * @covers Pattern\SimpleFactory\Pizza::setName 
    * @covers Pattern\SimpleFactory\Pizza::getName 
    */ 
    public function testPizzaSetsAndReturnsTheExpectedName() 
    { 
    $pizzaName = 'Greek Pizza'; 
    $this->pizza->setName($pizzaName); 
    $this->assertEquals($pizzaName, $this->pizza->getName()); 
    } 

    /** 
    * @covers Pattern\SimpleFactory\Pizza::setDescription 
    * @covers Pattern\SimpleFactory\Pizza::getDescription 
    */ 
    public function testPizzaSetsAndReturnsTheExpectedDescription() 
    { 
    $pizzaDescription = 'A Pepperoni-style pizza with dough, tomato, and cheese'; 
    $this->pizza->setDescription($pizzaDescription); 
    $this->assertEquals($pizzaDescription, $this->pizza->getDescription()); 
    } 

} 

PizzaStoreTest.php:

<?php namespace Pattern\SimpleFactory; 

use PHPUnit_Framework_TestCase; 

class PizzaStoreTest extends PHPUnit_Framework_TestCase { 

    /** 
    * @covers Pattern\SimpleFactory\PizzaStore::order 
    */ 
    public function testStoreShouldReturnsTheRequestedPizzaWhenOrdered() 
    { 
    $factory = new PizzaFactory(); 
    $store = new PizzaStore($factory); 
    $pizza = $store->order('greek'); 
    $this->assertInstanceOf('Pattern\SimpleFactory\Pizza', $pizza); 
    } 

} 

PizzaFactoryTest.php:

<?php namespace Pattern\SimpleFactory; 

use PHPUnit_Framework_TestCase; 

class PizzaFactoryTest extends PHPUnit_Framework_TestCase { 

    /** 
    * @var PizzaFactory 
    */ 
    private $pizzaFactory; 

    public function setUp() 
    { 
    $this->pizzaFactory = new PizzaFactory(); 
    } 

    /** 
    * @covers Pattern\SimpleFactory\PizzaFactory::make 
    */ 
    public function testPizzaFactoryMakesAPizza() 
    { 
    $pizza = $this->pizzaFactory->make('greek'); 
    $this->assertInstanceOf('Pattern\SimpleFactory\Pizza', $pizza); 
    } 

    /** 
    * @covers Pattern\SimpleFactory\PizzaFactory::make 
    */ 
    public function testPizzaFactoryReturnsNullWhenMakingANonexistentPizza() 
    { 
    $pizza = $this->pizzaFactory->make(null); 
    $this->isNull($pizza); 
    } 

} 

PizzaStore.php:

<?php namespace Pattern\SimpleFactory; 

/** 
* @package Pattern\SimpleFactory 
*/ 
class PizzaStore { 

    /** 
    * @var PizzaFactory 
    */ 
    private $factory; 

    /** 
    * @param PizzaFactory $factory 
    */ 
    function __construct(PizzaFactory $factory) 
    { 
    $this->factory = $factory; 
    } 

    /** 
    * @param string $name 
    * @return null|Pizza 
    */ 
    public function order($name) 
    { 
    return $this->factory->make($name); 
    } 

} 

PizzaFactory.php:

<?php namespace Pattern\SimpleFactory; 

/** 
* @package Pattern\SimpleFactory 
*/ 
class PizzaFactory { 

    /** 
    * @var array 
    */ 
    private $pizzas = [ 
    'greek'  => 'Pattern\SimpleFactory\Pizza\Greek', 
    'pepperoni' => 'Pattern\SimpleFactory\Pizza\Pepperoni', 
    ]; 

    /** 
    * @param string $name 
    * @return null|Pizza 
    */ 
    public function make($name) 
    { 
    if (isset($this->pizzas[$name])) 
    { 
     return new $this->pizzas[$name]; 
    } 

    return null; 
    } 

} 

Pizza.php:

<?php namespace Pattern\SimpleFactory; 

/** 
* @package Pattern\SimpleFactory 
*/ 
abstract class Pizza { 

    /** 
    * @var string 
    */ 
    private $name; 
    /** 
    * @var string 
    */ 
    private $description; 

    /** 
    * @return string 
    */ 
    public function getName() 
    { 
    return $this->name; 
    } 

    /** 
    * @param string $name 
    */ 
    public function setName($name) 
    { 
    $this->name = $name; 
    } 

    /** 
    * @return string 
    */ 
    public function getDescription() 
    { 
    return $this->description; 
    } 

    /** 
    * @param string $description 
    */ 
    public function setDescription($description) 
    { 
    $this->description = $description; 
    } 

} 

比薩\ Pepperoni.php:

<?php namespace Pattern\SimpleFactory\Pizza; 

use Pattern\SimpleFactory\Pizza; 

/** 
* @package Pattern\SimpleFactory\Pizza 
*/ 
class Pepperoni extends Pizza { 

    function __construct() 
    { 
    parent::setName('Pizza Pepperoni'); 
    parent::setDescription('A Pepperoni-style pizza with dough, tomato, and cheese'); 
    } 

} 

比薩\希臘.php:

<?php namespace Pattern\SimpleFactory\Pizza; 

use Pattern\SimpleFactory\Pizza; 

/** 
* @package Pattern\SimpleFactory\Pizza 
*/ 
class Greek extends Pizza { 

    function __construct() 
    { 
    parent::setName('Pizza Greek'); 
    parent::setDescription('A Greek-style pizza with feta cheese, onion, olive and tomato'); 
    } 

} 

就是這樣,有什麼不對,請說出來。先謝謝你。

回答

4

工廠負責實例化類和測試這個 我有模擬類的實例,用一個具體的類這樣我 ,它的工作原理,但是當我看到測試覆蓋率, 具體類出現,並沒有100%測試。 (你會理解 )。 - 我想避免這種情況,我想測試工廠爲儘可能抽象的 。

PizzaStore類中丟失的覆蓋率是由於您在工廠未找到類時未測試大小寫而造成的。

缺少測試案例:

/** 
* @covers Pattern\SimpleFactory\PizzaStore::order 
*/ 
public function testStoreShouldReturnsTheRequestedPizzaWhenOrdered() 
{ 
    $factory = new PizzaFactory(); 
    $store = new PizzaStore($factory); 
    $pizza = $store->order('not exists pizza type'); 
    $this->assertNull($pizza); 
} 

而另一個問題是,我要插入的工廠作爲構造 依賴,如何檢驗呢?

您可以使用模擬PizzaFactory類,然後驗證被調用。我不知道在PHPUnit這項工作是如何嘲笑,但在ouzo-goodies模擬工具,這看起來像:

public function testFactory() 
{ 
    $factory = Mock::create('\Pattern\SimpleFactory\PizzaFactory'); 
    Mock::when($factory)->make()->thenReturn(new \Pattern\SimpleFactory\Pizza\Greek()); 

    $magic = new Magic($factory); 

    $order = $magic->order(); 

    Mock::verify($factory)->make(); 
    $this->assertInstanceOf('\Pattern\SimpleFactory\Pizza\Greek', $order); 
} 

該方法PizzaFactory::make被稱爲該Mock::verify方法檢查。

另外在我看來你的情況更好使用interface over inheritance

+0

其實缺少測試是不需要的。 'PizzaFactory'是返回nulll的一個,如果你看看測試,你會發現'testPizzaFactoryReturnsNullWhenMakingANonexistentPizza' - 'PizzaStore'不是100%,因爲沒有經過測試的構造函數。這就是我想知道的,如何測試接受參數的構造函數。 - 而希臘比薩出現在測試覆蓋率爲0%,因爲我正在使用具體的類來測試工廠。如何在沒有具體類的情況下模擬工廠 - 在這種情況下,接口繼承的含義是什麼? – yayuj 2015-02-01 13:31:30