我似乎在测试私有实例变量设置时遇到了一些麻烦。我的想法是删除类并将实例变量公开,以便我可以测试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
,但是方法确实存在,所以我不知所措。
答案 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;