Phpunit 测试是否调用了受保护的方法

Phpunit 测试是否调用了受保护的方法,phpunit,Phpunit,我试图测试在公共接口中是否调用了受保护的方法 <?php abstract class SomeClassAbstract { abstract public foo(); public function doStuff() { $this->_protectedMethod(); } protected function _protectedMethod(); { // implemen

我试图测试在公共接口中是否调用了受保护的方法

<?php
abstract class SomeClassAbstract
{ 
    abstract public foo();

    public function doStuff() 
    {    
        $this->_protectedMethod();
    }

    protected function _protectedMethod();
    {
        // implementation is irrelevant
    }
}

<?php
class MyTest extends PHPUnit_Framework_TestCase
{
    public function testCalled()
    {
        $mock = $this->getMockForAbstractClass('SomeClass');
        $mock->expects($this->once())
             ->method('_protectedMethod');

        $mock->doStuff();
    }
}

在我拥有的PHPUnit版本中,类
PHPUnit\u Framework\u MockObject\u Mock
使用PHP的
get\u class\u方法来确定被模拟对象的接口
get\u class\u方法
将仅选择公共方法,而不是受保护或私有方法

这符合xUnit单元测试的精神。考虑PHPUnice文档的如何使用的例子。在那里,SUT是
主题
,它有一个受保护的方法
通知
。不过,正在测试的方法是
doSomething
。考虑到
Subject
是一个黑盒子,我们不关心它是如何实现的细节。不过,我们确实关心它的行为。具体来说,我们要求在调用
doSomething
时,调用任何附加观察者的
update
方法。因此,我们模拟第三方对象
Observer
,并设置调用其
update
方法的期望。请注意,尽管执行了受保护的方法
notify
,但在测试中没有显式命名。这使我们可以随时自由地更改实现,只要行为得到保留

回到你的例子

class MyTest extends PHPUnit_Framework_TestCase
{
  public function testCalled()
  {
    $mock = $this->getMock('SomeClass');
    $mock->expects($this->once())
         ->method('_protectedMethod');

    $mock->doStuff();
  }
}

在这里,您的
testCalled
方法不会创建被测系统(SUT)的实例,这将是SomeClass。SomeClass模拟中的
doStuff
版本没有任何作用。特别是,它不调用
\u protectedMethod

,看起来您只需要告诉PHPUnit您想要模拟该函数,即:

$mock = $this->getMock('SomeClass',
                        array('_protectedMethod'));
$mock->expects($this->once())
     ->method('_protectedMethod');

$mock->doStuff();

谢谢你,伊万,你说得对。当然,如果它是一个模拟对象,它就没有方法的实现。我是多么愚蠢啊。我会认为你的答案是正确的。如果可以的话,请看我的第二次编辑。所以我要测试的是实现,而不是行为,对吗?这对我来说更清楚一点,谢谢。我认为,单元测试比它看起来更像一门艺术。在阅读了GerardMeszaros的《xUnit测试模式:重构测试代码》之后,我更加欣赏它。反过来,这本书是PHPUnit作家塞巴斯蒂安·伯格曼(Sebastian Bergmann)的强烈推荐。
$mock = $this->getMock('SomeClass',
                        array('_protectedMethod'));
$mock->expects($this->once())
     ->method('_protectedMethod');

$mock->doStuff();