2016-01-23 36 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') 
     ); 
    } 
}