【问题标题】:PHPUnit mocks - assert method calledPHPUnit mocks - 调用断言方法
【发布时间】:2013-04-19 09:36:15
【问题描述】:

我是 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 次。

我哪里错了?

【问题讨论】:

    标签: methods mocking phpunit


    【解决方案1】:

    这完全取决于您想要测试什么以及您想要模拟什么。根据您的测试名称,我假设您想要测试 exchangeArray 方法。

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

    所以,如果你想测试 exchangeArray 方法并模拟 getInputFilter 你应该在第二个参数中传递“getInputFilter”,如下所示:

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

    但要小心。你没有告诉你的模拟返回任何东西,所以它会返回空值。这意味着您将在exchangeArray 方法的第二行出现致命错误(尝试在非对象上调用方法)。你应该准备一些伪造的过滤器对象来处理,例如:

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

    如果你想调用“真实的”getInputFilter 方法 - 那么你就不能模拟这个方法。

    【讨论】:

    • 感谢您的回复。我已经实现了这两种方法。我只是想检查方法是否以正确的顺序调用,然后使用特定参数调用它们。有什么方法可以检查方法是否在没有模拟对象的情况下被调用?
    • 不,没有。但是如果你想调用第二种方法,你不需要检查它是否真的被调用了,因为如果不是,那么你就不会得到 $inputFilter 对象并且你无论如何测试都会失败。
    • 另一方面,如果您的测试通过并且没有调用第二种方法(在您的情况下不会发生,但在某些情况下会发生),您会在代码覆盖率报告中注意到这一点。这可能意味着您只是不需要第二个电话,或者您已经修复了您的测试。如果您的第二个方法设置了一些内部对象属性,您还可以针对该属性进行测试,以检查该方法是否被调用。
    猜你喜欢
    • 2019-11-15
    • 2016-10-04
    • 2013-09-15
    • 2013-10-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多