我创建了以下示例测试用例:
<?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's Eloquent,似乎两种方法调用都可以在那里:
// Eloquent example without initial instantiation is possible too
$user = User::find(1);
无论如何,无论我的代码是否有效,我都希望能够模拟这些静态声明的方法。在阅读时,PHPUnit 似乎不能很好地处理静态方法(我读到有一个 staticExpect 方法,但现在从 PHPUnit 3.8 开始已弃用)。所以我即将开始尝试一些替代的测试框架(Codeception和AspectMock,PHPSpec,mockery),因为我对其他人没有太多经验。非常感谢有关此问题的一些指示或有关此问题的建议,因为它也确实有助于对我们公司的遗留应用程序进行单元测试,谢谢
答案是AspectMock。此库为以下问题提供了答案:
您将如何伪造 time() 函数以为每个测试调用生成相同的结果?有没有办法存根类的静态方法?你能在运行时重新定义类方法吗?
在静态定义方法之前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')
);
}
}