亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在 PHPUnit 中,當返回值是復雜對象時我應該如何測試

在 PHPUnit 中,當返回值是復雜對象時我應該如何測試

PHP
收到一只叮咚 2022-07-22 16:46:04
我有3節課。class Box{    public $item1;    public $item2;    public function __construct($item1,$item2){        $this->item = $item1;        $this->item2 = $item2;    }    public function getItem1(){        return $this->item1;    }}class Details{    public $stuff    public $item1;    public $item2;    public $item3;    public function __construct($stuff){       $this->stuff = $stuff    }    public function setItem1($item){        $this->item1 = $item;    }    public function setItem2($item){        $this->item2 = $item;    }}class Crate{    public $box;    private $stuffString = "Stuff";    public function __construct(Box $box){        $this->box = $box;    }    public function getDetails(){        $details = new Details($stuffString);        $details->setItem1($box->item1);        $details->setItem2("Detail");        return $details;    }}該Crate->getDetails()方法返回一個帶有來自 Box 對象的數據的 Details 對象。我想為此方法編寫測試。function test_get_details(){    $box = Mockery::mock(Box::class);    $box->shouldReceive('getItem1')->andReturn("BoxItem");    $crate= new Crate($box);    $details = $crate->getDetails();    $this->assertInstanceOf(Details::class,$details);}我創建了 Box 類的模擬并將其傳遞給 Crate 的構造函數。當我調用$crate->getDetails();它時,它應該返回一個 Details 對象$item1 = "盒子物品"$item2 = "詳細信息"$item3 = 空我知道我可以通過對每個項目$this->assertEquals("BoxItem",$details->item1);等進行測試...但這是最好的方法嗎?是否有一些 PHPUnit 工具來構建所需的詳細信息結果并進行比較例如$this->assertEquals(MockDetailObject,$details)還是我必須做一系列的斷言來確保結果是我所期望的。筆記*對于我的示例,我知道這沒什么大不了的,我快速構建它以解釋我的意思。但是在我正在處理的代碼中,我遇到了相同類型的問題,除了 Details 對象比 3 個字符串更復雜。
查看完整描述

2 回答

?
手掌心

TA貢獻1942條經驗 獲得超3個贊

創建工廠并 100% 測試該工廠。


據我了解,您的Crate班級既是實體又是工廠。Crate::getDetails您可以通過將此創建責任轉移到工廠來進行重構。


這樣,您就可以僅使用“Given, When, Then”結構對創建邏輯進行單元測試。查看這篇關于干凈測試的帖子并導航到“測試應該簡潔且有意義”。


擁有這種結構將幫助您分辨輸入和輸出是什么。例如:


CrateDetailsFactoryTest.php


class CrateDetailFactoryTest extends TestCase

{

    public function testCreateCrateDetail(): void

    {

        // Given

        $crate = $this->givenThereIsACrate();

        $boxes = $this->givenThereAreTwoRedBoxes();


        // When

        $crateDetail = $this->crateDetailFactory->createCrateDetail(

            $crate,

            $boxes

        );


        // Then

        // (Unnecessary instanceof, if you have strict return types)

        self::assertInstanceOf(Detail::class, $crateDetail);


        self::assertCount(2, $crateDetail->getBoxes());

        self::assertEquals(

            'red',

            $crateDetail->getBoxes()->first()->getColor()

        );

    }

}

有了這個,你的創建邏輯就被覆蓋了;從這里你可以簡單地在你需要的地方注入你的工廠,并且在單元測試期間你只是模擬它:


板條箱服務.php


class CrateServiceTest extends TestCase

{

    private $crateDetailFactory;


    private $crateService;


    public function setUp(): void

    {

        $this->crateDetailFactory = $this->prophesize(CrateDetailFactory::class);


        $this->crateService = new CrateService(

            $this->crateDetailFactory->reveal()

        );

    }


    public function testAMethodThatNeedsCrateDetails(): void

    {

        // Given

        $crate = $this->givenIHaveACrateWithTwoBoxesInIt();

        $boxes = $crate->getBoxes();


        // When

        $result = $this->crateService->AMethodThatNeedsCrateDetails();


        // Then

        $this->crateDetailFactory->createCrateDetail($crate, $boxes)

            ->shouldBeCalledOnce();

    }

}

我希望這很有用。干杯! :)


查看完整回答
反對 回復 2022-07-22
?
寶慕林4294392

TA貢獻2021條經驗 獲得超8個贊

使用上面的類,要正確地對其進行單元測試,您必須使用 DI 注入\Details::class其中一個getDetails()或 __constructor。然后為每個類的每個方法編寫測試,模擬任何類依賴項/屬性


class Create

{

    public function getDetails(\Details $details)

}


//test.php

$mockDetails = $this->createMock(\Details::class)

                           ->expects($this-once())

                           ->method('item1')

                           ->with('some_arg')

                           ->willReturn('xyz')


$mockBox = $this-createMock(\Box::class)

   ......


$crate = new Create($boxMock);

$result = $crate->item1($mockDetails);

$this-assertSame('xyz', $result);

如果對一種方法感覺像您的嘲笑方式,那么您應該考慮重構以使代碼更具可測試性。


至于多個項目的斷言,在 PHPUnit 中,您可以使用 dataprovider 將一組值作為單獨的測試傳遞給一個測試方法。 PHPUnit Docs - 數據提供者


您還可以為 \Details::class 編寫單獨的單元測試,斷言傳遞給 \Details::setItem1($item) 的內容實際上是在 item1 屬性上設置的。IE。


測試 \Details::class -


//test2


public function test() {

    $details = new Details('some stuff');

    $details->setItem1('expected');

    self::assertSame('expected', $details->item1); 

}


查看完整回答
反對 回復 2022-07-22
  • 2 回答
  • 0 關注
  • 102 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號