首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >如何为抽象类设置模拟的受保护属性?

如何为抽象类设置模拟的受保护属性?
EN

Stack Overflow用户
提问于 2016-08-31 19:05:26
回答 2查看 3.4K关注 0票数 5

我环顾四周,发现了一种适用于普通对象的解决方案,但它似乎不适用于模拟。

下面的测试失败的消息是:Unable to set property someProperty of object type Mock_ClassToTest_40ea0b83: Property someProperty does not exist

代码语言:javascript
代码运行次数:0
运行
复制
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更新代码响应凯蒂的答复

EN

回答 2

Stack Overflow用户

发布于 2016-08-31 19:25:29

您正在尝试调用模拟对象上的反射方法,相反,您可以在抽象类本身上调用它:

因此,改变:

代码语言:javascript
代码运行次数:0
运行
复制
$reflection = new ReflectionClass(get_class($object));

代码语言:javascript
代码运行次数:0
运行
复制
$reflection = new ReflectionClass(ClassToTest::class);

这将适用于类中不抽象的任何内容,如您的属性或其他完全实现的方法。

自OP更新后的附加说明

修复仍然适用于getReflectionProperty中的第一行。但是,如果您没有访问类名的权限,那么这就是一个问题。

票数 3
EN

Stack Overflow用户

发布于 2016-08-31 21:19:54

在测试中使用反射来访问受保护的私有属性和类的方法似乎是一种非常聪明的方法,但它会导致难以阅读和理解的测试。

另一方面,只应该测试类的公共接口。测试(甚至关心)被测试类的受保护的私有属性和方法是测试是在代码之后编写的一个标志。这样的测试是脆弱的;被测试类的实现中的任何更改都会破坏测试,即使它不会破坏类的功能。

通常不需要测试抽象类。大多数情况下,它的子类的测试也涵盖了抽象类的相关代码。如果它们没有覆盖其中的某些部分,那么要么不需要该代码,要么测试用例不涵盖所有的角用例。

但是,有时需要为抽象类编写一个测试用例。在我看来,最好的方法是在包含测试用例的文件底部扩展抽象类,为其所有抽象方法提供简单的实现,并将该类作为苏特使用。

类似于这样的东西:

代码语言:javascript
代码运行次数:0
运行
复制
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协作者在测试中不适合实例化的行为。

在测试中模拟协作类的原因包括,但不限于:

  • 创建困难;例如,当模拟类的构造函数需要许多参数或其他对象时;
  • 协作者是一个抽象类或接口,在编写测试和测试类时,实际的实现甚至可能不存在;
  • 协作者的代码需要大量时间来完成或需要额外的资源(磁盘空间、数据库连接、Internet连接等);
  • 协作者的代码具有永久的副作用;这通常与前面的原因结合在一起。
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39257217

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档