Methods PHPUnit mocks-assert方法调用

Methods PHPUnit mocks-assert方法调用,methods,mocking,phpunit,Methods,Mocking,Phpunit,我是phpunit的新手,读过关于模拟对象的文档,但不太清楚 我正试图编写一个简单的测试来断言调用类中的方法。使用以下代码,我正在测试当调用Client::exchangeArray时,是否调用了Client::getInputFilter class Client implements InputFilterAwareInterface { public function getInputFilter() { if(!$this->_inputFilter){

我是phpunit的新手,读过关于模拟对象的文档,但不太清楚

我正试图编写一个简单的测试来断言调用类中的方法。使用以下代码,我正在测试当调用Client::exchangeArray时,是否调用了Client::getInputFilter

class Client implements InputFilterAwareInterface
{

public function getInputFilter() {
    if(!$this->_inputFilter){
        $inputFactory = new InputFactory();
        $inputFilter = new InputFilter();

        $inputFilter->add($inputFactory->createInput(array(
            'name' => 'id',
            'required' => true,
            'filters' => array(
                array(
                    'name' => 'Int'
                )
            )
        )));

        $inputFilter->add($inputFactory->createInput(array(
            'name' => 'name',
            'required' => true,
            'filters' => array(
                array(
                    'name' => 'StripTags'
                ),
                array(
                    'name' => 'StringTrim'
                ),
                array(
                     'name' => 'StripNewLines'      
                ),
                array(
                    'name' => 'Alpha'
                )
            ),
            'validators' => array(
                array(
                    'name' => 'StringLength',
                    'options' => array(
                        'encoding' => 'UTF-8',
                        'min' => 2,
                        'max' => 100
                    )
                )
            )
        )));

        $inputFilter->add($inputFactory->createInput(array(
            'name' => 'surname',
            'required' => true,
            'filters' => array(
                array(
                    'name' => 'StripTags'
                ),
                array(
                    'name' => 'StringTrim'
                )
            ),
            'validators' => array(
                array(
                    'name' => 'StringLength',
                    'options' => array(
                        'encoding' => 'UTF-8',
                        'min' => 2,
                        'max' => 100
                    )
                )
            )
        )));

        $inputFilter->add($inputFactory->createInput(array(
            'name' => 'email',
            'required' => false,
            'filters' => array(
                array(
                    'name' => 'StripTags'
                ),
                array(
                    'name' => 'StringTrim'
                )
            ),
            'validators' => array(
                array(
                    'name' => 'StringLength',
                    'options' => array(
                        'encoding' => 'UTF-8',
                        'min' => 2,
                        'max' => 150
                    )
                ),
                array(
                    'name' => 'EmailAddress'
                )
            )
        )));

        $this->_inputFilter = $inputFilter;
    }
    return $this->_inputFilter;
}

public function exchangeArray($data){
    $inputFilter = $this->getInputFilter();
    $inputFilter->setData($data);
    if(!$inputFilter->isValid()){
        throw new \Exception('Invalid client data'); 
    }

    $cleanValues = $inputFilter->getValues();

    $this->_id = (isset($cleanValues['id']) ? $cleanValues['id'] : null);
    $this->_name = (isset($cleanValues['name']) ? $cleanValues['name'] : null);
    $this->_surname = (isset($cleanValues['surname']) ? $cleanValues['surname'] : null);
    $this->_email = (isset($cleanValues['email']) ? $cleanValues['email'] : null);
    }        
}
以下是我的测试用例:

public function testExchangeArrayCallsInputFilter(){
    $data = array('id' => 54,
            'name' => 'john',
            'surname' => 'doe',
            'email' => 'john.doe@domain.com'
    );

    $mock = $this->getMock('Client', array('exchangeArray'));
    $mock->expects($this->once())
         ->method('getInputFilter');
    $mock->exchangeArray($data);
}
…我得到了以下错误:

方法名称等于的预期失败 调用1次时。方法应被调用1次, 实际上打了0次电话


我哪里出错了?

这完全取决于您想要什么测试和想要什么模拟。基于测试的名称,我假设您需要测试
exchangeArray
方法

getMock
方法将要模拟的方法的名称作为第二个参数。这意味着他们永远不会被召唤

因此,如果您想要测试
exchangeArray
方法和模拟
getInputFilter
,您应该在第二个参数中传递“getInputFilter”,如下所示:

$mock = $this->getMock('Client', array('getInputFilter'));
$mock->expects($this->once())
     ->method('getInputFilter');
$mock->exchangeArray($data);
但是要小心。您没有告诉您的mock返回任何内容,因此它将返回null值。这意味着您将在
exchangeArray
方法的第二行出现致命错误(尝试在非对象上调用方法)。你应该准备一些伪造的过滤对象来处理,例如:

// $preparedFilterObject = ...
$mock = $this->getMock('Client', array('getInputFilter'));
$mock->expects($this->once())
    ->method('getInputFilter')
    ->will($this->returnValue($preparedFilterObject);
$mock->exchangeArray($data);

如果你想调用“real”
getInputFilter
方法,那么你就不能模仿这个方法。

谢谢你的回复。我已经有了这两种方法的实现。我只是想检查方法的调用顺序是否正确,然后检查是否使用特定参数调用它们。有没有办法检查在没有模拟对象的情况下调用方法?没有。但是,如果你想调用第二个方法,你不需要检查它是否真的被调用了,因为如果它没有被调用,那么你就不会得到$inputFilter对象,你的测试也会失败。另一方面,如果你的测试通过了,第二个方法没有被调用(在你的情况下不会发生,但在某些情况下可能发生),你会在代码覆盖率报告中注意到这一点。这可能意味着你不需要第二次呼叫,或者你已经修复了测试。如果您的第二个方法设置了一些内部对象属性,您还可以针对该属性进行测试,以检查是否调用了该方法。