继承的Setter方法不会设置重写的实例变量

时间:2013-10-31 19:58:02

标签: php inheritance phpunit getter-setter

我似乎在测试私有实例变量设置时遇到了一些麻烦。我的想法是删除类并将实例变量公开,以便我可以测试setter方法。这看起来很简单,但我似乎无法让它正常工作。或者可能有一些更好的方法来测试设置私有变量。

<?php
namespace PureChat\src\messages;

/**
 * Message class for containing information about a message.
 */
class Message
{
    /**
     * Contains the message text.
     * @var string
     */
    private $messageText;

    /**
     * Sets the instance variable $messageText.
     * @param string $text The text to assign.
     */
    public function setText($text)
    {
        $this->messageText = $text;
    }
}

PHPUnit测试

<?php
use PureChat\src\messages\Message;

class MessageTest extends \PHPUnit_Framework_TestCase
{
    public function testMessageCanSetText()
    {
        $message = new MessageStub;
        $message->setText('test-text');
        $this->assertEquals(
            $message->messageText, 'test-text');
    }
}

class MessageStub extends Message
{
    public $messageText;
}

运行时,测试失败,"Failed asserting that 'test-text' matches expected null."我首先想到的是,存根类可能没有继承setText方法,所以我也测试了method_exists,但是方法确实存在,所以我不知所措。

2 个答案:

答案 0 :(得分:1)

私有属性不会被继承,因此$messageText已经不在MessageStub类中。并且它不能由继承的方法setText设置。

然后你以错误的顺序使用assertEquals()个参数:第一个应该是你期望的值,第二个是你测试的值。翻转参数 - 然后错误消息更有意义,因为当前消息显示您期望NULL - 但您希望字符串'test-text'。

然后我们来讨论测试哲学的主题。一个好的单元测试只检查一个对象的外部,但不应该关心内部工作。如果设置了一个值,那么设置它的成功应该可以从外部检测到。当你只有非常基本的setter / getter组合时,测试它们确实很无聊,但这就是你应该做的:设置一个有效的值,把它取回来,断言它和以前一样,断言没有错误发生了(这是由PHPUnit自动完成的,因为任何PHP错误或异常都会导致测试失败)。

如果没有该值的getter - 要么设置值无用,因为它从未使用过,或者您可以通过测试使用该值的部分来测试它。

$message->setText('foo');
$message->saveText(); // uses value from setText()

如果你想测试一下,你可能会在一次测试中调用这两种方法。而且你需要测试单独调用saveText会触发错误。或者保存默认值。

或者您得出的结论是,使用两种方法做一件事并不是一个好主意,因为测试它们并不容易,因此您的测试经验可能会让您考虑改进该消息对象的API。你可能想以某种方式摆脱setText方法。

是的,使用Reflection来访问私有属性是一种测试它的方法。但是现在您将测试严格绑定到对象的内部构造。如果重命名私有属性,则测试会中断 - 但它不应该因为您没有更改公共接口而中断。

答案 1 :(得分:0)

您可以使用reflection

$message = new Message;
$message->setText('test-text');

$property = (new \ReflectionObject($message))->getProperty('messageText');
$property->setAccessible(true);
$value = $property->getValue($message);
$property->setAccessible(false); // restore state

echo $value;