簡體   English   中英

如何使用過程代碼庫在PHP中編寫單元測試?

[英]How do I write unit tests in PHP with a procedural codebase?

我基本上相信單元測試的好處,我想開始將這個概念應用於用PHP編寫的大型現有代碼庫。 不到10%的代碼是面向對象的。

我看了幾個單元測試框架(PHPUnit,SimpleTest和phpt)。 但是,我沒有找到測試過程代碼的任何示例。 什么是我的情況最好的框架,有沒有使用非OOP代碼單元測試PHP的例子?

你可以對程序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);
    }

希望這可以幫助。

什么單元測試做得很好,以及你應該使用它們的是,當你有一段代碼,你提供了一些輸入,並且你希望得到一些輸出。 我們的想法是,當您稍后添加功能時,您可以運行測試並確保它仍然以相同的方式執行舊功能。

因此,如果您有一個過程代碼庫,則可以在測試方法中完成此函數調用

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等產品,您最好花時間在“驗收測試”級別。 這些將允許您自動化瀏覽器,然后檢查頁面中的內容作為特定位置/表單。

您可以嘗試將非oop代碼包含到測試類中

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' );
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM