2015-10-28 44 views
2

鑑於我有一個FruitSalad類(待測系統):PHPUnit的已命名的靜態構造函數模擬類

class FruitSalad 
{ 
    protected $fruits = []; 

    public function addFruit(Fruit $fruit) 
    { 
     $this->fruits[] = $fruit; 
     return $this; 
    } 
} 

而且我有一個Fruit類:

class Fruit 
{ 
    public static function withName($name) 
    { 
     $instance = new MyDependencyClass(); 
     $instance->name = $name; 
     return $instance; 
    } 
} 

一個簡單的例子然而,你可以看到,Fruit類使用一個名爲靜態構造函數,並在FruitSalad類類型addFruit()方法暗示Fruit作爲其預期的參數。

在編寫addFruit()的測試時,我需要模擬Fruit類。

function test_it_can_add_a_fruit_to_its_list_of_fruits() 
{ 
    $fruit = $this->getMockBuilder('Fruit') 
     ->disableOriginalConstructor() 
     ->getMock(); 

    $this->fruitSalad->addFruit($fruit); 
    // Do some assertion. 
} 

這將創建Fruit類的簡單模擬,但我想通過withName()靜態方法來初始化它 - 我不希望暴露的name屬性的設置。

我如何創建使用靜態構造函數命名一個Fruit模擬?

+0

的理由輾轉::staticExpects()你想嘲笑'withName'?如果它應該啓動'Fruit'對象,則靜態方法是錯誤的選擇,請改用'__construct'。 另外,'withName'在你的例子中不會被調用,所以不應該嘲笑這個類是不夠的,或者你稍後調用該方法? – StoryTeller

+0

在我的例子中沒有使用它,因爲我需要一個模擬。我不想明確地使用''Fruit :: withName('Apple');'''模擬需要調用該靜態方法來返回對象。 – Amo

+1

順便說一句,有一個術語爲你的靜態「構造函數」 - _factory method_ –

回答

1

PHPUnit的用於支持嘲諷靜態方法,但由於PHPUnit的4.0它被省略。我在這裏看到四個選項:

1.在所有

不要嘲笑的方法你可以只調用該方法,並使用它的邏輯,但你會測試靜態方法,以及如果你這樣做通常這是編寫單元測試時應該避免的。

2.更改類

問問自己,如果這個方法真的需要是靜態的,如果沒有,更改類正確測試它。在一些用例中,爲了編寫正確的測試,最好更改一些架構。

3.使用間諜類

間諜類是擴展一個類,您通常會模仿,但實現一些邏輯測試類的測試方法的配置或依賴另一班方法。在絕大多數情況下,這可以通過適當地嘲笑課程來避免。如果嘲笑不夠,間諜只是你的工作,很少有你真正需要他們的情況。

然而,在這種情況下,間諜可以用來覆蓋一個靜態方法作爲一種解決方法:

class FruitSpy extends Fruit 
{ 

    public static $return; 

    public static $name; 

    public static function withName($name) { 
     $expected = self::$name; 
     if($name == $expected) { 
      return self::$return; 
     } else { 
      throw new \RuntimeException("FruitSpy::withName(): Parameter 0 was $name, $expected expected"); 
     } 
    } 

} 

本示例檢查是否正確$name,如果它是正確的,返回你所定義的回報。你會在你的測試中使用這樣的:

$fruitSpy = new FruitSpy(); 
$fruitSpy::$name = "Banana"; 
$fruitSpy::$return = new \stdClass(); 

$this->fruitSalad->addFruit($fruitSpy); 

不完全是一個乾淨的解決方案,但我認爲如果你絕對肯定不想更改其他代碼比測試代碼的唯一途徑。

同樣,如果您需要這樣做,您應該考慮將靜態方法更改爲臨時方法。

4.使用PHPUni 3. *

你可以簡單的使用PHPUnit的一個過時版本才能使用此方法。不是首選的方式。

結論

我沒有看到一個乾淨的方式來嘲笑一個靜態方法,並在4.0

0

如何創建使用水果靜態命名構造一個模擬的?

你不行。 Mock是通過使用模擬框架創建的。

反正它並沒有多麼嘲笑創建但是,相反,他們的言行舉止,因爲它們是外部類進行測試。

剛剛配置的模擬,使得它表現一個真正的水果實例將使用Fruit::withName創建時相同的方式。