为了坚持使用here:
的相同示例我现在想测试子类中受保护方法的实现 因为我在抽象类的测试中将它们存在,所以实现本身并未经过测试 但是,受保护的方法没有正常测试,所以我想了解你如何测试它们的建议。
就像my other thread一样,我想解决这个而不重构我的代码。
父级:
abstract class Order
{
public function __construct( $orderId, User $user )
{
$this->id = $this->findOrderId( $user->getId(), $orderId );
if ($this->id !== false) {
$this->setOrderData();
}
}
abstract protected function findOrderId( $userId, $orderIdToSearch );
private function setOrderData()
{
...
}
}
要测试的儿童班:
public class OrderTypeA extends Order
{
protected function findOrderId($userId, $orderId)
{
...
}
}
测试代码:
class OrderTypeATest extends PHPUnit_Framework_TestCase
{
public function testFindOrderId() {
???
}
}
答案 0 :(得分:1)
您可以使用反射测试受保护/私有方法。阅读此tutorial。在其他解决方案中,你会发现直接的解决方案:
/**
* Call protected/private method of a class.
*
* @param object &$object Instantiated object that we will run method on.
* @param string $methodName Method name to call
* @param array $parameters Array of parameters to pass into method.
*
* @return mixed Method return.
*/
public function invokeMethod(&$object, $methodName, array $parameters = array())
{
$reflection = new \ReflectionClass(get_class($object));
$method = $reflection->getMethod($methodName);
$method->setAccessible(true);
return $method->invokeArgs($object, $parameters);
}
另外,关于你的上一个问题,你试图测试抽象类。 phpunit mocking的解决方案必须有效。但是如果使用PHP 7,则可以使用Anonymous classes来获得相同的结果:
abstract class Order
{
protected $id;
public function __construct($orderId, $userId)
{
$this->id = $this->findOrderId($userId, $orderId);
if ($this->id !== false) {
$this->setOrderData();
}
}
abstract protected function findOrderId($userId, $orderIdToSearch);
private function setOrderData()
{
echo 'setOrderData';
}
}
$orderId = 1;
$userId = 1;
$order = new class($orderId, $userId) extends Order {
protected function findOrderId($userId, $orderIdToSearch)
{
return 1;
}
};
您将最终得到正在运行的 $ order 对象,该对象已准备好进行测试。最好将此代码放在测试用例的 setUp()方法中。
答案 1 :(得分:0)
如果您在订单找到正确时才获得有效的Generic.xaml
。做一些像:
$this->id
或$order = new OrderTypeA($orderId, $user);
$this->assertNotEquals(false,$order->id);
等于$orderId
$this->id
但是这里没有足够的代码/逻辑告诉你更多;)
答案 2 :(得分:0)
你的抽象对我没有意义。
我知道你有一个代表订单的对象。您通过提供用户和订单ID来实例化它。但是,有多种类型的订单,这些类型的订单之间的区别在于您在数据库存储中搜索它们的方式?这听起来不对。
您的代码确实讲述了一个奇怪的故事。您有此订单ID,您要做的第一件事就是搜索订单ID。我只是认为你已经拥有订单ID,所以不需要再次搜索它。或者该方法名称错误,而不是findOrderId()
,而应该将其称为findOrderById()
- 或findUserOrderById()
。
此外,您在构造函数中工作。不应该在那里搜索东西。
您的测试问题来自于您决定将不同的搜索策略实现为抽象方法。您必须测试受保护的抽象方法,这并不容易。它使得对主抽象订单类进行属性测试也很困难,因为你必须提供一个实现 - 而这个实现听起来像是隐藏了一个数据库访问层,所以实际代码中可能会出现很多问题。
我建议不要让订单自行搜索。搜索订单应在订单对象之外完成。这样,您可能会将搜索作为公共方法实现,可以进行常规测试。然后,搜索订单的代码将决定您是否已成功找到OrderTypeA
,或者可能缺少MissingOrderTypeA
,这两个版本都会延长订单类。订单对象应该包含订单数据,而不是搜索逻辑以在数据库中找到它们。
提示:如果您在测试代码时遇到问题,那么您的代码尝试以错误的方式执行操作的可能性为99.9%。这并不是说事情不能以这种方式完成,而是说你将要努力测试代码,这也难以维护,并且寻找替代策略来实现解决方案是个好主意。优雅的代码总是很容易测试,因为所有必要的方法在相关的类中是公开的,因此可以按预期一起工作。