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

时间:2009-11-05 13:36:44

标签: phpunit

我正在尝试测试是否在公共接口中调用受保护的方法。

<?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说它从未调用过。

当我以另一种方式测试时,当方法从不调用时,会发生同样的情况:

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

    public function doAnotherStuff() 
    {    
        $this->_loadCache();
    }

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

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

        $mock->doAnotherStuff();
    }
}

调用该方法,但PHPUnit表示它不是。

我做错了什么?

修改 我没有用双冒号声明我的方法,它只是表示它是一个公共方法(接口)。已更新为完整的类/方法声明。

编辑2 我应该说我在抽象类中测试一些方法实现(编辑代码以反映这一点)。由于我无法实例化该类,我该如何测试呢?

我正在考虑创建SomeClassSimple扩展SomeClassAbstract并对其进行测试。这是正确的做法吗?

2 个答案:

答案 0 :(得分:11)

在我所拥有的PHPUnit版本中,类PHPUnit_Framework_MockObject_Mock使用PHP的get_class_methods来确定被模拟对象的接口。 get_class_methods只会选择公共方法,而不是受保护方法或私有方法。

这符合xUnit单元测试的精神。考虑PHPUnit文档关于如何使用Mock Objects的示例。在那里,SUT是Subject,其具有受保护的方法notify。但是,正在测试的方法是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的 mock 中的doStuff版本没有做任何事情。特别是,它不会调用_protectedMethod

答案 1 :(得分:4)

看起来你只需告诉PHPUnit你要模拟这个函数,即:

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

$mock->doStuff();