2011-09-05 66 views
2

我正在重組遺留php項目的測試用例來測試套件,並遇到測試依賴於另一個類的類的問題。這是測試文件夾的原始目錄佈局。重新組織測試文件的選項,其中一個類依賴於另一個類?

tests/ 
    | 
    +- models/ 
    |  | ClassATest.php 
    |  | ClassBTest.php 
    |  | ... 
    +- controllers/ 
    |  | ... 

目前,沒有測試套件。每個測試都是分開運行的。

爲了重新組織這些測試,我創建了phpunit.xml並將測試分組到如下的套件中。

phpunit.xml

<phpunit bootstrap="..."> 
    <testsuite name="Models"> 
     <directory>./models</directory> 
    </testsuite> 
    ... 
</phpunit> 

現在我惹上麻煩。我們有兩個模型,ClassA和ClassB,ClassB的方法依賴於ClassA。

class ClassA 
{ 
    public function getValue(...) 
    { 
     ... 
    } 
} 

class ClassB 
{ 
    public function doSomething() 
    { 
     $a = new ClassA(); 
     $x = $a->getValue(...); 
     // do something with $x 
     ... 
    } 
} 

在這裏,我想我們都會在測試時看到問題。模擬ClassA :: getValue(),ClassBTest.php已經(重新)定義ClassA,如下所示。

ClassBTest.php

class ClassA 
{ 
    public function getValue(...) 
    { 
     return 'a mock value'; 
    } 
} 

class ClassBTest extends PHPUnit_Framework_TestCase 
{ 
    public function testDoSomething() 
    { 
     $b = new ClassB(); 
     // Make an assertion with $b->doSomething() 
    } 
} 

所以,當我們分別測試每一個模型,它的工作原理。但是,當在套件中運行時,它會導致錯誤,因爲現在ClassA在運行過程的某個點重新聲明,並且phpunit被終止。

我的問題是如何處理這種情況。我嘗試了一些選擇。

  • 刪除測試文件中的重新定義的類並使用依賴注入。這種方式並不是首選,因爲我們不想修改用於依賴注入的模型類。
  • 使用組註釋來排除這樣的測試文件,如ClassBTest.php並單獨運行排除的文件。這個選項不方便。

我們可以配置phpunit在一個進程中運行一組文件,在另一個進程中運行另一組文件嗎? PHP可以在運行時動態加載和卸載類嗎?如果您有其他選擇,請提出建議。

謝謝!

回答

2

PHP可以在運行時動態加載和卸載類嗎?如果您有其他選擇,請提出建議。

是的。這是測試您無法重構的代碼的最後手段。看看the runkit extension, method_rename。你可以重命名你想「模擬」的orignal方法。創建你的模擬函數,並在測試後重新命名它。

較新的php test helpers也提供重命名功能。


或者,您可以使用"runInIsolation"/"process-isolation"。每個測試用例都將在另一個PHP進程中運行。如果你只用測試用例來定義這些類,那麼你將不會遇到「已定義」的問題。


,不依賴於擴展或spawing很多PHP程序的,使您的測試套件慢

這似乎有點hackisch只是提供所有的選擇第三個選項:

class ClassB 
{ 
    public function doSomething() 
    { 
     $a = new ClassA(); 
     $x = $a->getValue(...); 
     // do something with $x 
     ... 
    } 
} 

沒有重構你可以到以下幾點:

class ClassB { public function doSomething() { $ a = $ this-> getClassA(); $ x = $ a-> getValue(...); //使用$ X 東西... }

protected function getClassA() { 
    if(!$this->classA) { 
     return new ClassA(); 
    } 
    return $this->classA; 
} 

public function setClassAForTesting(ClassA $classA) { 
    $this->classA = $classA; 
} 

}

雜波您的代碼庫 「爲測試代碼」,但使用setter injection允許您使用依賴注入測試時您的生產代碼將像以前一樣工作。

這種方法需要一些工作,但根據我的經驗,它比使用PHP擴展攻擊行爲更可持續。

+0

謝謝,edorian!與團隊討論使用php擴展和重構模型。可能我們會選擇第一個選項。如果phpunit允許我們在單獨的進程中運行每組文件,會不會很好?我們是否應該向Sebastian Bergmann提出特徵請求;) – peidiam

相關問題