2016-10-28 51 views
2

我有一個創建了PHP time()方法未成年包裝函數在我的課懲戒的包裝時間函數

class MyClass 
{ 
    public function myFuncion($unixTimeStamp) 
    { 
     $pending = $this->isPending($unixTimeStamp) 

     // data manipulation 

     return $result 
    } 

    protected function isPending($unixTimeStamp) 
    { 
     if ($unixTimeStamp > $this->currentTime()) { 
      return true; 
     } 

     return false; 
    } 

    public function currentTime() 
    { 
     return time(); 
    } 
} 

我想測試這個類中的公共職能myFunction()但我在一個有點損失如何我可以嘲笑currentTime方法而不嘲笑SUT本身(MyClass)

這樣做的正確方法是什麼?我覺得使用單一方法(getCurrentTime)創建一個時間類,然後將它注入MyClass,但是正確,過多,因爲我只在代碼中的一個地方檢查時間。

無論這是最好的方法嗎?

編輯:我正在考慮製作time特質,因爲它looks like PHPUnit的可以模擬這一點。仍然不確定這是否過度使用單一的方法..

我還有什麼其他的選擇?

回答

1

您可以以只修改的行爲創建測試類的部分模仿對象所選方法(currentTime方法)。爲了這個目的,你可以使用Mock Builder APIsetMethods

setMethods(數組$方法)可素生成器對象上調用 指定要與配置的測試 雙替換的方法。其他方法的行爲不會改變。如果您調用 setMethods(NULL),則不會替換任何方法。

那麼試試這個代碼(假設myFunction返回isPending方法的結果):

class MyClassTest extends \PHPUnit_Framework_TestCase 
{ 
    /** 
    * @test 
    */ 
    public function itShouldReturnTrueIfPendingState() 
    { 
     $currentTime = (new \DateTime('now -1 year'))->getTimestamp(); 

     /** @var MyClass|\PHPUnit_Framework_MockObject_MockObject $myClass */ 
     $myClass = $this->getMockBuilder(MyClass::class) 
      ->disableOriginalConstructor() 
      ->setMethods(['currentTime']) 
      ->getMock(); 

     $myClass 
      ->method('currentTime') 
      ->willReturn($currentTime); 

     $this->assertTrue($myClass->myFunction(time())); 
    } 

    /** 
    * @test 
    */ 
    public function itShouldReturnFalseIfNotState() 
    { 
     $currentTime = (new \DateTime('now +1 year'))->getTimestamp(); 


     /** @var MyClass|\PHPUnit_Framework_MockObject_MockObject $myClass */ 
     $myClass = $this->getMockBuilder(MyClass::class) 
      ->disableOriginalConstructor() 
      ->setMethods(['currentTime']) 
      ->getMock(); 

     $myClass 
      ->method('currentTime') 
      ->willReturn($currentTime); 

     $this->assertFalse($myClass->myFunction(time())); 
    } 
+1

我決定創建一個類,它注入了部分嘲諷SUT,雖然你的建議幫了不同的問題,所以謝謝 – myol

0

我們可以在命名空間級別覆蓋time()函數。檢查https://www.schmengler-se.de/en/2011/03/php-mocking-built-in-functions-like-time-in-unit-tests/

但倒臺是,每一個我們稱之爲time()時間將返回嘲笑的時間:)

namespace MyClass; 

function time() 
{ 
    return MyClassTest::$mockTime ?: \time(); 
} 

class MyClassTest extends TestCase{ 

    public static $mockTime; 

    public function test_my_function(){ 
     self::$mockTime = '08:10'; 
     $myClass = new MyClass(); 
     //$myClass->currentTime() //will return 08:10 
     //do something with my function 
    }