2009-05-22 47 views
28

我大多信服單元測試的好處,並且我想開始將這個概念應用到用PHP編寫的大型現有代碼庫中。這個代碼中不到10%是面向對象的。我看了幾個單元測試框架(PHPUnit,SimpleTest和phpt)。但是,我還沒有找到任何這些測試程序代碼的例子。什麼是我的情況的最佳框架,是否有使用非OOP代碼單元測試PHP的任何示例?如何使用程序代碼庫在PHP中編寫單元測試?

回答

34

你可以單元測試程序化PHP,沒問題。如果你的代碼和HTML混合在一起,那麼你絕對不會走運。

在應用程序或驗收測試級別,您的程序PHP可能依賴於超全局變量的值($_POST, $_GET, $_COOKIE等)來確定行爲,並以包含模板文件並吐出輸出結束。

要進行應用程序級別的測試,只需設置超全局值;啓動一個輸出緩衝區(以防止一堆html氾濫你的屏幕);呼叫該頁面;反對緩衝區內的東西;並在最後垃圾緩衝區。 所以,你可以做這樣的事情:

public function setUp() 
{ 
    if (isset($_POST['foo'])) { 
     unset($_POST['foo']); 
    } 
} 

public function testSomeKindOfAcceptanceTest() 
{ 
    $_POST['foo'] = 'bar'; 
    ob_start(); 
    include('fileToTest.php'); 
    $output = ob_get_flush(); 
    $this->assertContains($someExpectedString, $output); 
} 

即使是巨大的,有很多的包括,這種測試會告訴你,如果你有工作或沒有應用級功能「框架」。當你開始改進你的代碼時,這是非常重要的,因爲即使你確信數據庫連接器仍然工作並且看起來比以前更好,你還是需要單擊一個按鈕,看看是的,你仍然可以通過數據庫登錄和註銷。

在較低級別,取決於變量範圍以及函數是否通過副作用(返回true或false),或者直接返回結果,有較小的變化。

變量是否顯式傳遞,作爲函數之間的參數或參數數組?或者是變量設置在許多不同的地方,並作爲全局變量隱式傳遞?如果是(良好的)明確的情況,你可以通過(1)包括保存函數的文件,然後(2)直接提供函數測試值,以及(3)捕獲輸出並針對它進行斷言來單元測試函數。如果你使用全局變量,你只需要特別小心(如上面的$ _POST例子),以便在測試之間仔細地清空所有的全局變量。在處理推動和拉動大量全局變量的函數時,保持測試非常小(5-10行,1-2斷言)也特別有用。

另一個基本問題是函數是通過返回輸出還是通過改變傳入的參數來返回true/false。在第一種情況下,測試是比較容易的,但再一次,它可能在兩種情況下:

// assuming you required the file of interest at the top of the test file 
public function testShouldConcatenateTwoStringsAndReturnResult() 
{ 
    $stringOne = 'foo'; 
    $stringTwo = 'bar'; 
    $expectedOutput = 'foobar'; 
    $output = myCustomCatFunction($stringOne, $stringTwo); 
    $this->assertEquals($expectedOutput, $output); 
} 

在不好的情況下,你的代碼工作的副作用並返回true或false,你仍然可以很容易地測試:

/* suppose your cat function stupidly 
* overwrites the first parameter 
* with the result of concatenation, 
* as an admittedly contrived example 
*/ 
public function testShouldConcatenateTwoStringsAndReturnTrue() 
    { 
     $stringOne = 'foo'; 
     $stringTwo = 'bar'; 
     $expectedOutput = 'foobar'; 
     $output = myCustomCatFunction($stringOne, $stringTwo); 
     $this->assertTrue($output); 
     $this->Equals($expectedOutput, $stringOne); 
    } 

希望這會有所幫助。

1

你可以嘗試以包括非面向對象的代碼到使用

require_once 'your_non_oop_file.php' # Contains fct_to_test() 

而且在PHPUnit定義你的測試功能的測試類:

testfct_to_test() { 
    assertEquals(result_expected, fct_to_test(), 'Fail with fct_to_test'); 
} 
+0

這看起來像一個有趣的解決方案,但是如果大多數邏輯不涉及函數而是簡單的循環和條件,會怎樣呢? – 2009-05-22 19:03:23

+5

然後,你已經得到了一大杯「幫助意大利麪代碼」。 – 2009-05-22 19:08:35

+0

我認爲Travis沒有使用html的php代碼。 – 2009-05-22 19:15:42

6

什麼單元測試做的很好,什麼你應該使用它們,當你有一段代碼給出了一些輸入,並且你期望得到一些輸出數量。這個想法是,當您稍後添加功能時,您可以運行測試並確保它仍然以相同的方式執行舊功能。

所以,如果你有一個程序代碼庫,你可以在測試方法

require 'my-libraries.php'; 
class SomeTest extends SomeBaseTestFromSomeFramework { 
    public function testSetup() { 
     $this->assertTrue(true); 
    } 

    public function testMyFunction() { 
     $output = my_function('foo',3); 

     $this->assertEquals('expected output',$output); 
    } 
} 

這一招用PHP代碼庫中,往往你的庫代碼將與正在運行的干擾完成這個調用你的函數因爲您的代碼庫和測試框架將包含許多與在Web瀏覽器中設置應用程序環境(會話,共享全局變量等)相關的代碼。希望花些時間來達到可以包含庫代碼並運行簡單測試的目的(上面的testSetup函數)。

如果你的代碼沒有函數,並且只是一系列輸出HTML頁面的PHP文件,那你的確有點不走運。你的代碼不能分成不同的單元,這意味着單元測試對你來說不會有多大用處。您最好花一些時間在SeleniumWatir等產品的「驗收測試」級別。這些將讓您自動瀏覽器,然後檢查頁面內容爲特定位置/表單。

相關問題