php PHPUnit 模拟对象和静态方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2357001/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PHPUnit Mock Objects and Static Methods
提问by rr.
I am looking for the best way to go about testing the following static method (specifically using a Doctrine Model):
我正在寻找测试以下静态方法的最佳方法(特别是使用 Doctrine 模型):
class Model_User extends Doctrine_Record
{
public static function create($userData)
{
$newUser = new self();
$newUser->fromArray($userData);
$newUser->save();
}
}
Ideally, I would use a mock object to ensure that "fromArray" (with the supplied user data) and "save" were called, but that's not possible as the method is static.
理想情况下,我会使用模拟对象来确保调用“fromArray”(使用提供的用户数据)和“save”,但这是不可能的,因为该方法是静态的。
Any suggestions?
有什么建议?
采纳答案by Gordon
Sebastian Bergmann, the author of PHPUnit, recently had a blog post about Stubbing and Mocking Static Methods. With PHPUnit 3.5 and PHP 5.3 as well as consistent use of late static binding, you can do
PHPUnit 的作者 Sebastian Bergmann 最近发表了一篇关于Stubbing 和 Mocking Static Methods的博客文章。使用 PHPUnit 3.5 和 PHP 5.3 以及一致使用后期静态绑定,您可以做到
$class::staticExpects($this->any())
->method('helper')
->will($this->returnValue('bar'));
Update:staticExpectsis deprecated as of PHPUnit 3.8and will be removed completely with later versions.
更新:staticExpects被弃用的PHPUnit 3.8的,将被更高版本的完全去除。
回答by treeface
There is now the AspectMock library to help with this:
现在有 AspectMock 库来帮助解决这个问题:
https://github.com/Codeception/AspectMock
https://github.com/Codeception/AspectMock
$this->assertEquals('users', UserModel::tableName());
$userModel = test::double('UserModel', ['tableName' => 'my_users']);
$this->assertEquals('my_users', UserModel::tableName());
$userModel->verifyInvoked('tableName');
回答by b01
I would make a new class in the unit test namespace that extends the Model_User and test that. Here's an example:
我会在单元测试命名空间中创建一个新类来扩展 Model_User 并对其进行测试。下面是一个例子:
Original class:
原班级:
class Model_User extends Doctrine_Record
{
public static function create($userData)
{
$newUser = new self();
$newUser->fromArray($userData);
$newUser->save();
}
}
Mock Class to call in unit test(s):
在单元测试中调用的模拟类:
use \Model_User
class Mock_Model_User extends Model_User
{
/** \PHPUnit\Framework\TestCase */
public static $test;
// This class inherits all the original classes functions.
// However, you can override the methods and use the $test property
// to perform some assertions.
}
In your unit test:
在您的单元测试中:
use Module_User;
use PHPUnit\Framework\TestCase;
class Model_UserTest extends TestCase
{
function testCanInitialize()
{
$userDataFixture = []; // Made an assumption user data would be an array.
$sut = new Mock_Model_User::create($userDataFixture); // calls the parent ::create method, so the real thing.
$sut::test = $this; // This is just here to show possibilities.
$this->assertInstanceOf(Model_User::class, $sut);
}
}
回答by gealex
The doublitlibrary could also help you to test static methods :
该doublit库还可以帮助你测试静态方法:
/* Create a mock instance of your class */
$double = Doublit::mock_instance(Model_User::class);
/* Test the "create" method */
$double::_method('create')
->count(1) // test that the method is called once
->args([Constraints::isInstanceOf('array')]) // test that first argument is an array
->stub('my_value') // stub the method to return "myvalue"
回答by Leonid Shagabutdinov
Another possible approach is with the Mokalibrary:
另一种可能的方法是使用Moka库:
$modelClass = Moka::mockClass('Model_User', [
'fromArray' => null,
'save' => null
]);
$modelClass::create('DATA');
$this->assertEquals(['DATA'], $modelClass::$moka->report('fromArray')[0]);
$this->assertEquals(1, sizeof($modelClass::$moka->report('save')));
回答by Pascal MARTIN
Testing static methods is generally considered as a bit hard (as you probably already noticed), especially before PHP 5.3.
测试静态方法通常被认为有点困难(您可能已经注意到),尤其是在 PHP 5.3 之前。
Could you not modify your code to not use static a method ? I don't really see why you're using a static method here, in fact ; this could probably be re-written to some non-static code, could it not ?
您不能修改您的代码以不使用静态方法吗?事实上,我真的不明白你为什么在这里使用静态方法;这可能会被重写为一些非静态代码,不是吗?
For instance, could something like this not do the trick :
例如,这样的事情是否可以解决问题:
class Model_User extends Doctrine_Record
{
public function saveFromArray($userData)
{
$this->fromArray($userData);
$this->save();
}
}
Not sure what you'll be testing ; but, at least, no static method anymore...
不确定你要测试什么;但是,至少,不再有静态方法了......

