我创建了以下示例测试用例:
<?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
关键字时,我似乎工作正常,然后我的测试通过了。但是我希望我的Model类在其他情况下也允许调用某些方法而不必首先实例化:
// 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'));
我遇到过这个博客,其中指出静态声明但动态调用的方法是可以的。但是,动态声明但静态调用的方法将引发STRICT错误 - http://www.lornajane.net/posts/2010/declaring-static-methods-in-php
之前我也使用过Laravel的Eloquent,似乎两种方法都可以调用:
// Eloquent example without initial instantiation is possible too
$user = User::find(1);
无论如何,无论我的代码是否有效,我都希望能够模拟静态声明的这些方法。看来PHPUnit似乎没有很好地处理静态方法(我读过有一个staticExpects方法,但现在已经弃用了PHPUnit 3.8)。所以我即将开始尝试一些替代测试框架(Codeception和AspectMock,PHPSpec,嘲弄),因为我对其他人没有多少经验。非常感谢关于这个问题的一些指示或关于此事的建议,因为它对我们公司的遗留应用程序的单元测试也非常有帮助,谢谢
答案 0 :(得分:0)
答案是AspectMock。 该库为这些问题提供了答案:
你如何伪造time()函数来为每次测试调用产生相同的结果?有没有办法存根类的静态方法?你能在运行时重新定义一个类方法吗?
答案 1 :(得分:0)
在静态定义$this->user->factory
方法之前,您无法致电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')
);
}
}