Reputation: 261
i'm new to phpunit and have read the documentation on mock objects but it isn't very clear.
I am trying to write a simple test that asserts a method within a class is called. With the following code, i am testing that when the Client::exchangeArray is called, a call is made to 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);
}
}
Here is my test case:
public function testExchangeArrayCallsInputFilter(){
$data = array('id' => 54,
'name' => 'john',
'surname' => 'doe',
'email' => '[email protected]'
);
$mock = $this->getMock('Client', array('exchangeArray'));
$mock->expects($this->once())
->method('getInputFilter');
$mock->exchangeArray($data);
}
...and i'm getting the following error:
Expectation failed for method name is equal to when invoked 1 time(s). Method was expected to be called 1 times, actually called 0 times.
Where am i going wrong?
Upvotes: 24
Views: 42722
Reputation: 11364
It all depends on what you want test and what you want mock. Basing on the name of your test I assume that you want test exchangeArray
method.
The getMock
method takes as second argument names of methods that you want mock. It means that they will never be called.
So, if you want to test exchangeArray
method and mock getInputFilter
you should pass "getInputFilter"
in second argument, like below:
$mock = $this->getMock('Client', array('getInputFilter'));
$mock->expects($this->once())
->method('getInputFilter');
$mock->exchangeArray($data);
But be careful. You didn't tell your mock to return anything, so it will return null value. That means that you'll get a fatal error on the second line of exchangeArray
method (trying to call a method on a non-object). You should prepare some faked filter object to deal with that, eg:
// $preparedFilterObject = ...
$mock = $this->getMock('Client', array('getInputFilter'));
$mock->expects($this->once())
->method('getInputFilter')
->will($this->returnValue($preparedFilterObject);
$mock->exchangeArray($data);
And if you want to invoke the "real" getInputFilter
method - then you just can't mock this method.
Upvotes: 23