是否可以使用禁用的构造函数和手动设置的受保护属性创建模拟对象?
这是一个愚蠢的例子:
class A {
protected $p;
public function __construct(){
$this->p = 1;
}
public function blah(){
if ($this->p == 2)
throw Exception();
}
}
class ATest extend bla_TestCase {
/**
@expectedException Exception
*/
public function testBlahShouldThrowExceptionBy2PValue(){
$mockA = $this->getMockBuilder('A')
->disableOriginalConstructor()
->getMock();
$mockA->p=2; //this won't work because p is protected, how to inject the p value?
$mockA->blah();
}
}
Run Code Online (Sandbox Code Playgroud)
所以我想注入受保护的p值,所以我不能.我应该定义setter或IoC,还是我可以用phpunit来做这个?
gon*_*lez 53
您可以使用Reflection将属性设为公共属性,然后设置所需的值:
$a = new A;
$reflection = new ReflectionClass($a);
$reflection_property = $reflection->getProperty('p');
$reflection_property->setAccessible(true);
$reflection_property->setValue($a, 2);
Run Code Online (Sandbox Code Playgroud)
无论如何,在您的示例中,您不需要为要引发的异常设置p值.您正在使用模拟来控制对象行为,而不考虑它的内部.
因此,不是设置p = 2而是引发Exception,而是在调用blah方法时将mock配置为引发异常:
$mockA = $this->getMockBuilder('A')
->disableOriginalConstructor()
->getMock();
$mockA->expects($this->any())
->method('blah')
->will($this->throwException(new Exception));
Run Code Online (Sandbox Code Playgroud)
最后,你在嘲笑ATest中的A类很奇怪.您通常会模拟正在测试的对象所需的依赖项.
希望这可以帮助.
小智 19
以为我会留下一个方便的助手方法,可以在这里快速复制和粘贴:
/**
* Sets a protected property on a given object via reflection
*
* @param $object - instance in which protected value is being modified
* @param $property - property on instance being modified
* @param $value - new value of the property being modified
*
* @return void
*/
public function setProtectedProperty($object, $property, $value)
{
$reflection = new ReflectionClass($object);
$reflection_property = $reflection->getProperty($property);
$reflection_property->setAccessible(true);
$reflection_property->setValue($object, $value);
}
Run Code Online (Sandbox Code Playgroud)