5

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

<?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和测试这个。这是正确的方法吗?

4

2 回答 2

10

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

这符合 xUnit 单元测试的精神。考虑 PHPUnit 文档中关于如何使用Mock Objects的示例。在那里,SUT 是Subject,它有一个受保护的方法notify。但是,正在测试的方法是doSomething. 作为Subject一个黑盒子,我们并不关心它是如何实现的细节。不过,我们确实关心它的行为。具体来说,我们要求在调用 时,调用任何附加的观察者doSomethingupdate方法。所以我们模拟了第三方对象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中的版本没有做任何事情。特别是,它不调用._protectedMethod

于 2009-11-05T14:37:33.763 回答
3

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

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

$mock->doStuff();
于 2010-06-11T03:37:06.960 回答