我环顾四周,发现了一种适用于普通对象的解决方案,但它似乎不适用于模拟。
下面的测试失败的消息是:Unable to set property someProperty of object type Mock_ClassToTest_40ea0b83: Property someProperty does not exist
。
class sampleTestClass extends PHPUnit_Framework_TestCase
{
function test() {
$object = $this->getMockForAbstractClass(ClassToTest::class, [], '', false);
$this->setProtectedProperty($object, 'someProperty', 'value');
}
private function getReflectionProperty($object, $property) {
$reflection = new ReflectionClass($object);
$reflectionProperty = $reflection->getProperty($property);
$reflectionProperty->setAccessible(true);
return $reflectionProperty;
}
/**
* This method modifies the protected properties of any object.
* @param object $object The object to modify.
* @param string $property The name of the property to modify.
* @param mixed $value The value to set.
* @throws TestingException
*/
function setProtectedProperty(&$object, $property, $value) {
try {
$reflectionProperty = $this->getReflectionProperty($object, $property);
$reflectionProperty->setValue($object, $value);
}
catch ( Exception $e ) {
throw new TestingException("Unable to set property {$property} of object type " . get_class($object) .
': ' . $e->getMessage(), 0, $e);
}
}
}
abstract class ClassToTest
{
private $someProperty;
abstract function someFunc();
}
class TestingException extends Exception
{
}
编辑: 8/31/2016 4:32下午EST更新代码响应凯蒂的答复。
发布于 2016-08-31 11:25:29
您正在尝试调用模拟对象上的反射方法,相反,您可以在抽象类本身上调用它:
因此,改变:
$reflection = new ReflectionClass(get_class($object));
至
$reflection = new ReflectionClass(ClassToTest::class);
这将适用于类中不抽象的任何内容,如您的属性或其他完全实现的方法。
自OP更新后的附加说明
修复仍然适用于getReflectionProperty中的第一行。但是,如果您没有访问类名的权限,那么这就是一个问题。
发布于 2016-08-31 13:19:54
在测试中使用反射来访问受保护的私有属性和类的方法似乎是一种非常聪明的方法,但它会导致难以阅读和理解的测试。
另一方面,只应该测试类的公共接口。测试(甚至关心)被测试类的受保护的私有属性和方法是测试是在代码之后编写的一个标志。这样的测试是脆弱的;被测试类的实现中的任何更改都会破坏测试,即使它不会破坏类的功能。
通常不需要测试抽象类。大多数情况下,它的子类的测试也涵盖了抽象类的相关代码。如果它们没有覆盖其中的某些部分,那么要么不需要该代码,要么测试用例不涵盖所有的角用例。
但是,有时需要为抽象类编写一个测试用例。在我看来,最好的方法是在包含测试用例的文件底部扩展抽象类,为其所有抽象方法提供简单的实现,并将该类作为苏特使用。
类似于这样的东西:
class sampleTestClass extends PHPUnit_Framework_TestCase
{
public function testSomething()
{
$object = new ConcreteImplementation();
$result = $object->method1();
self::assertTrue($result);
}
}
class ConcreteImplementation extends AbstractClassToTest
{
public function someFunc()
{
// provide the minimum implementation that makes it work
}
}
您正在测试您发布的代码中的一个模拟。模拟是不打算进行测试的。它们的目的是模拟SUT协作者在测试中不适合实例化的行为。
在测试中模拟协作类的原因包括,但不限于:
https://stackoverflow.com/questions/39257217
复制相似问题