在 PHPUnit 中,如何模擬不屬於類別的函數?
P粉216807924
P粉216807924 2023-10-29 15:44:54
0
2
704

我目前正在從事的專案包含物件導向和流程化 PHP 程式碼的混合。所以我有這樣的東西:

function doStuff($value)
{
    $x = $value + 1;

    return $x;
}

class MyClass
{
    private $field;

    public function setMyValue($amount)
    {
        $this->field = doStuff($amount) + doStuff(2 * $amount);
    }
}

這些依賴項有幾個,但是很少(一隻手就能數出來)。但是,我需要為類別編寫單元測試(使用 PHPUnit),我不知道如何模擬來自程式端的函數(在本例中為 doStuff)。據我所知,PHPUnit 中的模擬功能僅適用於類別。

我會在沒有任何模擬的情況下完成它,但問題是其中一些函數執行一些 IO 操作;我認為不以某種方式嘲笑他們並不是一個好主意。

我該如何解決這個問題?

P粉216807924
P粉216807924

全部回覆(2)
P粉275883973

我看到的唯一選項是依賴注入,因為您的類別想要使用類別外部的資源。因此,這打破了一些封裝規則。

我過去是如何做到這一點的,是將這些函數放在自己的類別中並要求/包含它們,並且當設定測試變數時,包含一個具有相同的半“模擬”函數的基本文件,該文件傳回已知狀態。

我的另一種方法是建立一個簡單的 UTILITY 類,其中包含所有這些資料函數,然後使用依賴項注入和模擬來進行測試。

class Utilities
{

    function doStuff($value)
    {
        $x = $value + 1;
        return $x;
    }
}

class MyClass
{
    private $UtilitiesObject;

    private $field;

    public function setMyValue($amount)
    {
//        $this->field = doStuff($amount) + doStuff(2 * $amount);
        $this->field = $this->UtilitiesObject->doStuff($amount) + $this->UtilitiesObject->doStuff(2 * $amount);
    }
}

    // Constructor Injection, pass the Utilities object here
    public function __construct($Utilities = NULL)
    {
        if(! is_null($Utilities) )
        {
            if($Utilities instanceof Utilities)
            {
                $this->SetUtilities($Utilities);
            }
        }
    }

    function SetUtilities(Utilities $Utilities)
    {
        $this->UtilitiesObject = $Utilities
    }

}

測試:

class UtilitiesTest extends PHPUnit_Framework_TestCase
{

    // Could also use dataProvider to send different returnValues, and then check with Asserts.
    public function testSetMyValue()
    {
        // Create a mock for the Utilities class,
        // only mock the doStuff() method.
        $MockUtilities = $this->getMock('Utilities', array('doStuff'));

        // Set up the expectation for the doStuff() method 
        $MockUtilities->expects($this->any())
                    ->method('doStuff')
                    ->will($this->returnValue(1));

        // Create Test Object - Pass our Mock as the Utilities
        $TestClass = new MyClass($MockUtilities);
        // Or
        // $TestClass = new MyClass();
        // $TestClass->SetUtilitiess($MockUtilities);

        // Test doStuff
        $amount = 10;   // Could be checked with the Mock functions
        $this->assertEquals(2, $TestClass->doStuff($amount));       // Mock always returns 1, so 1+1=2
    }
}
P粉155832941

當您從名稱空間呼叫函數(在全域名稱空間中定義)並且始終將它們稱為不合格的函數時,您可以利用 PHP 的命名空間回退策略

這允許您透過在呼叫者的命名空間內提供函數來建立模擬。

為了讓您的生活變得特別輕鬆,我將其打包到庫中 php-mock- phpunit 可以與 PHPUnit 一起使用:

namespace foo;

use phpmock\phpunit\PHPMock;

class BuiltinTest extends \PHPUnit_Framework_TestCase
{

    use PHPMock;

    public function testTime()
    {
        $time = $this->getFunctionMock(__NAMESPACE__, "time");
        $time->expects($this->once())->willReturn(3);

        $this->assertEquals(3, time());
    }
}
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板