2016-01-23 86 views
0

我創建了下面的例子測試用例:如何嘲笑在PHP中靜態聲明的方法時,單元測試

<?php 

abstract class Model 
{ 
    //... 

    public static function factory($data) 
    { 
     $className = get_called_class(); 
     $obj = new $className($data); 
     return $obj; 
    } 
} 

class User extends Model 
{ 

} 

class ExampleController 
{ 
    protected $user; 

    public function __construct(User $user) 
    { 
     $this->user = $user; 
    } 

    public function create() 
    { 
     return $this->user->factory(array('name' => 'Jim')); 
    } 
} 

class ExampleTest extends PHPUnit_Framework_TestCase 
{ 
    public function testSomething() 
    { 
     $user = new User(array('name' => 'Jim')); 

     $modelStub = $this->getMockBuilder('User') 
      ->disableOriginalConstructor() 
      ->getMock(); 

     $modelStub 
      ->method('factory') 
      ->with(array('name' => 'Jim')) 
      ->willReturn($user); 

     $example = new ExampleController($modelStub); 

     $this->assertEquals($user, $example->create()); 
    } 
} 

不過,我得到以下錯誤:

1) ExampleTest::testSomething 
PHPUnit_Framework_MockObject_BadMethodCallException: 

我似乎好工作,當我刪除static關鍵字,然後我的測試通過。但我想我的模型類中,也允許,在其他情況下,可以選擇調用某些方法,而無需先實例:

// when instantiation is required 
$userModel = new User(); 
$user = $userModel->factory(array('name' => 'Jim')); 

// called statically, no initial instantiation required 
$user = User::factory(array('name' => 'Jim')); 

我碰到這個博客裏面說的方法靜態聲明,但動態地叫出來,是好。然而,方法動態申報,但靜態調用,將引發嚴格的錯誤 - http://www.lornajane.net/posts/2010/declaring-static-methods-in-php

我也用Laravel雄辯之前,看來,這兩種方法調用可能有:

// Eloquent example without initial instantiation is possible too 
$user = User::find(1); 

無論如何,不​​管無論我的代碼是否工作,我希望能夠模擬靜態聲明這些方法。讀起來似乎PHPUnit並沒有很好地處理靜態方法(我讀過那裏有一個staticExpects方法,但現在不推薦使用PHPUnit 3.8)。所以我即將開始嘗試一些其他的測試框架(Codeception和AspectMock,PHPSpec,嘲笑),因爲我沒有太多的經驗與其他人。真的很感謝這個問題的一些建議或者對這個問題的建議,因爲在我們公司對遺留應用程序進行單元測試真的有幫助,謝謝

+2

沒有工具可以模擬靜態方法。儘可能避免靜態方法的另一個原因。 –

+0

您正在將該方法聲明爲static,但將其稱爲類方法:'return $ this-> user-> factory(array('name'=>'Jim'));' – hek2mgl

回答

0

答案是AspectMock。 這個庫給出了這個問題的答案:

你會如何僞造time()函數來爲每個測試調用產生相同的結果?有什麼方法來存根類的靜態方法嗎?你可以在運行時重新定義類方法嗎?

0

除非您有靜態定義的factory方法,否則不能調用$this->user->factory。您應該將其更改爲User::factory。你可以嘲笑這種靜態方法與Moka

class ExampleController 
{ 
    private $_userClass; 

    public function __construct($userClass = 'User') 
    { 
     $this->_userClass = $userClass; 
    } 

    public function create() 
    { 
     return $this->_userClass::factory(array('name' => 'Jim')); 
    } 
} 

class ExampleControllerTest extends \PHPUnit_Framework_TestCase 
{ 
    public function testCreateReturnsUser() 
    { 
     $userClass = Moka::stubClass(null, ['::factory' => 'USER']); 
     $controller = new ExampleController($userClass); 
     $this->assertEquals('USER', $controller->create()); 

     $this->assertEquals( 
      [[['name' => 'Jib']], 
      $userClass::$moka->report('::factory') 
     ); 
    } 
}