CodeIgniter4 測(cè)試入門(mén)

2020-08-17 17:42 更新

CodeIgniter的構(gòu)建旨在使對(duì)框架和應(yīng)用程序的測(cè)試盡可能簡(jiǎn)單。PHPUnit內(nèi)置對(duì)它的支持,并且該框架提供了許多方便的輔助方法,以使您的應(yīng)用程序的各個(gè)方面的測(cè)試盡可能輕松。

系統(tǒng)設(shè)置

安裝phpUnit

CodeIgniter使用phpUnit作為所有測(cè)試的基礎(chǔ)。有兩種方法可以安裝phpUnit以在系統(tǒng)中使用。

Composer

推薦的方法是使用Composer將其安裝在項(xiàng)目中。盡管可以在全球范圍內(nèi)安裝它,但我們不建議您這樣做,因?yàn)殡S著時(shí)間的流逝,它可能會(huì)導(dǎo)致與系統(tǒng)上其他項(xiàng)目的兼容性問(wèn)題。

確保系統(tǒng)上已安裝Composer。在項(xiàng)目根目錄(包含應(yīng)用程序和系統(tǒng)目錄的目錄)中,從命令行鍵入以下內(nèi)容:

> composer require --dev phpunit/phpunit

這將為您當(dāng)前的PHP版本安裝正確的版本。完成后,您可以通過(guò)鍵入以下內(nèi)容運(yùn)行該項(xiàng)目的所有測(cè)試:

> ./vendor/bin/phpunit

Phar

另一個(gè)選擇是從phpUnit網(wǎng)站下載.phar文件。這是一個(gè)獨(dú)立文件,應(yīng)放置在項(xiàng)目根目錄下。

測(cè)試您的應(yīng)用程序

PHPUnit配置

框架phpunit.xml.dist在項(xiàng)目根目錄中有一個(gè)文件。這控制了框架本身的單元測(cè)試。如果您提供自己的phpunit.xml,它將超越此。

phpunit.xml應(yīng)該排除的system文件夾,以及任何vendorThirdParty文件夾,如果你是單元測(cè)試您的應(yīng)用程序。

測(cè)試類

為了利用所提供的其他工具,您的測(cè)試必須擴(kuò)展CIUnitTestCase。默認(rèn)情況下,所有測(cè)試均應(yīng)位于tests / app目錄中。

要測(cè)試新庫(kù)Foo,您可以在tests / app / Libraries / FooTest.php中創(chuàng)建一個(gè)新文件:

<?php namespace App\Libraries;


use CodeIgniter\Test\CIUnitTestCase;


class FooTest extends CIUnitTestCase
{
    public function testFooNotBar()
    {
        . . .
    }
}

要測(cè)試您的模型之一,您可能會(huì)在以下代碼中得到以下結(jié)果tests/app/Models/OneOfMyModelsTest.php

<?php namespace App\Models;


use CodeIgniter\Test\CIUnitTestCase;


class OneOfMyModelsTest extends CIUnitTestCase
{
    public function testFooNotBar()
    {
        . . .
    }
}

您可以創(chuàng)建適合您的測(cè)試樣式/需求的任何目錄結(jié)構(gòu)。為測(cè)試類命名時(shí),請(qǐng)記住app目錄是App名稱空間的根,因此您使用的任何類都必須具有相對(duì)于的正確名稱空間App。

注解

測(cè)試類并非嚴(yán)格要求使用名稱空間,但是它們有助于確保沒(méi)有類名沖突。

測(cè)試數(shù)據(jù)庫(kù)結(jié)果時(shí),必須使用CIDatabaseTestClass類。

附加斷言

CIUnitTestCase 提供了其他可能有用的單元測(cè)試斷言。

assertLogged($ level,$ expectedMessage)

確保您希望實(shí)際記錄的內(nèi)容是:

$config = new LoggerConfig();
$logger = new Logger($config);


... do something that you expect a log entry from
$logger->log('error', "That's no moon");


$this->assertLogged('error', "That's no moon");

assertEventTriggered($ eventName)

確保您希望觸發(fā)的事件實(shí)際上是:

Events::on('foo', function($arg) use(&$result) {
    $result = $arg;
});


Events::trigger('foo', 'bar');


$this->assertEventTriggered('foo');

assertHeaderEmitted($ header,$ ignoreCase = false)

確保實(shí)際上發(fā)出了標(biāo)頭或cookie:

$response->setCookie('foo', 'bar');


ob_start();
$this->response->send();
$output = ob_get_clean(); // in case you want to check the actual body


$this->assertHeaderEmitted("Set-Cookie: foo=bar");

注意:與此相關(guān)的測(cè)試案例應(yīng)在PHPunit中作為單獨(dú)的進(jìn)程運(yùn)行

assertHeaderNotEmitted($ header,$ ignoreCase = false)

確保沒(méi)有發(fā)出標(biāo)題或cookie:

$response->setCookie('foo', 'bar');


ob_start();
$this->response->send();
$output = ob_get_clean(); // in case you want to check the actual body


$this->assertHeaderNotEmitted("Set-Cookie: banana");

注意:與此相關(guān)的測(cè)試案例應(yīng)在PHPunit中作為單獨(dú)的進(jìn)程運(yùn)行。

assertCloseEnough($ expected,$ actual,$ message ='',$ tolerance = 1)

對(duì)于延長(zhǎng)的執(zhí)行時(shí)間測(cè)試,請(qǐng)測(cè)試預(yù)期時(shí)間與實(shí)際時(shí)間之間的絕對(duì)差是否在規(guī)定的公差內(nèi):

$timer = new Timer();
$timer->start('longjohn', strtotime('-11 minutes'));
$this->assertCloseEnough(11 * 60, $timer->getElapsedTime('longjohn'));

上述測(cè)試將允許實(shí)際時(shí)間為660或661秒。

assertCloseEnoughString($ expected,$ actual,$ message ='',$ tolerance = 1)

對(duì)于延長(zhǎng)的執(zhí)行時(shí)間測(cè)試,測(cè)試預(yù)期時(shí)間與實(shí)際時(shí)間之間的絕對(duì)差(格式為字符串)是否在規(guī)定的公差范圍內(nèi):

$timer = new Timer();
$timer->start('longjohn', strtotime('-11 minutes'));
$this->assertCloseEnoughString(11 * 60, $timer->getElapsedTime('longjohn'));

上述測(cè)試將允許實(shí)際時(shí)間為660或661秒。

訪問(wèn)受保護(hù)的/私有的屬性

測(cè)試時(shí),可以使用以下setter和getter方法訪問(wèn)要測(cè)試的類中的受保護(hù)的方法和私有方法以及屬性。

getPrivateMethodInvoker($ instance,$ method)

使您可以從類外部調(diào)用私有方法。這將返回一個(gè)可以調(diào)用的函數(shù)。第一個(gè)參數(shù)是要測(cè)試的類的實(shí)例。第二個(gè)參數(shù)是您要調(diào)用的方法的名稱。

// Create an instance of the class to test
$obj = new Foo();


// Get the invoker for the 'privateMethod' method.
    $method = $this->getPrivateMethodInvoker($obj, 'privateMethod');


// Test the results
    $this->assertEquals('bar', $method('param1', 'param2'));

getPrivateProperty($ instance,$ property)

從類的實(shí)例中檢索私有/受保護(hù)的類屬性的值。第一個(gè)參數(shù)是要測(cè)試的類的實(shí)例。第二個(gè)參數(shù)是屬性的名稱。

// Create an instance of the class to test
$obj = new Foo();


// Test the value
$this->assertEquals('bar', $this->getPrivateProperty($obj, 'baz'));

setPrivateProperty($ instance,$ property,$ value)

在類實(shí)例中設(shè)置一個(gè)受保護(hù)的值。第一個(gè)參數(shù)是要測(cè)試的類的實(shí)例。第二個(gè)參數(shù)是要為其設(shè)置值的屬性的名稱。第三個(gè)參數(shù)是將其設(shè)置為的值:

// Create an instance of the class to test
$obj = new Foo();


// Set the value
$this->setPrivateProperty($obj, 'baz', 'oops!');


// Do normal testing...

模擬服務(wù)

您通常會(huì)發(fā)現(xiàn)您需要模擬app / Config / Services.php中定義的服務(wù)之一,以將測(cè)試限制為僅涉及代碼,同時(shí)模擬服務(wù)的各種響應(yīng)。在測(cè)試控制器和其他集成測(cè)試時(shí)尤其如此。該服務(wù)類提供了兩個(gè)方法,使這個(gè)簡(jiǎn)單的:injectMock()reset()。

injectMock()

此方法允許您定義Services類將返回的確切實(shí)例。您可以使用它來(lái)設(shè)置服務(wù)的屬性,使其以某種方式運(yùn)行,或者將服務(wù)替換為模擬類。

public function testSomething()
{
    $curlrequest = $this->getMockBuilder('CodeIgniter\HTTP\CURLRequest')
                        ->setMethods(['request'])
                        ->getMock();
    Services::injectMock('curlrequest', $curlrequest);


    // Do normal testing here....
}

第一個(gè)參數(shù)是您要替換的服務(wù)。該名稱必須與Services類中的函數(shù)名稱完全匹配。第二個(gè)參數(shù)是要替換為的實(shí)例。

reset()

從Services類中刪除所有模擬的類,使其恢復(fù)到原始狀態(tài)。

流過(guò)濾器

CITestStreamFilter提供了這些輔助方法的替代方法。

您可能需要測(cè)試難以測(cè)試的事物。有時(shí),捕獲流(例如PHP自己的STDOUT或STDERR)可能會(huì)有所幫助。將CITestStreamFilter幫助您從您所選擇的流捕獲輸出。

在您的一個(gè)測(cè)試用例中演示此示例:

public function setUp()
{
    CITestStreamFilter::$buffer = '';
    $this->stream_filter = stream_filter_append(STDOUT, 'CITestStreamFilter');
}


public function tearDown()
{
    stream_filter_remove($this->stream_filter);
}


public function testSomeOutput()
{
    CLI::write('first.');
    $expected = "first.\n";
    $this->assertEquals($expected, CITestStreamFilter::$buffer);
}
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)