Reputation: 5947
Hi guys I have a method that given a determinate situation it call it self, an short example of the method can be:
class MyClass
{
protected $quantity;
public function add($quantity)
{
for($i = 0; $i < $quantity; $i++)
{
$newQuantity = $quantity - 1;
$this->setQuantity($newQuantity);
$this->add($this->quantity);
}
return $this->quantity;
}
public function setQuantity($quantity)
{
$this->quantity = $quantity;
}
}
If I want to write a test for this ugly method (Just for purpose of example), I will do something like so:
<?php
use Mockery as m;
class TestMyClass
{
public function teardown()
{
m::close();
}
public function test_add_method()
{
// Here come the problem because I need to mock that the method
// will be called, but if I mock it, I cannot call it for an
// assertion
$mockMyClass = m::mock('MyClass[setQuantity,add]');
$mockClass->shouldReceive('setQuantity')
->once()
->with(1)
->andReturn(null);
$result = $mockMyClass->add(1); // Here the problem
$this->assertEquals(0,$result);
}
}
But how I wrote the comments above the code, I cannot properly mock the method add
because I need to do an assertion to it, but is even true that will be called again and I should accomplish the behaviour of it.
error track running this unit test:
Method Mockery_1_Mocks_My_Class::add() does not exist on this mock object
How do you achieve a test for this small function?
Upvotes: 2
Views: 2737
Reputation: 70863
Basic rule of thumb: You don't mock the class you are about to test, period.
There may be cases where this rule seems to not apply, but all these cases indicate that your class is doing too many things, needs to be split into parts, and all the parts you are then not testing can be mocked.
Now you seem to be trying to mock something because you want to test for the internal recursive calls. Don't. Because it is irrelevant to the outside world how the result is achieved, be it recursively or iteratively. You can always convert recursive code into interative code and vice versa, the only difference being that one approach usually is more fitting to the problem.
So in essence you want to do something like this:
public function test_add_one()
{
$myClass = new MyClass();
$result = $myClass->add(1);
$this->assertEquals(0,$result);
}
public function test_add_two()
{
$myClass = new MyClass();
$result = $myClass->add(2);
$this->assertEquals(0,$result); // I totally made this one up, haven't checked the code in detail
}
If the test functions look like this, and you see no benefit testing that whatever parameter you pass to the add method, the return value is always zero, this might be related to your example code not showing any other place where a value change triggered by code execution can be observed.
Upvotes: 3
Reputation: 1856
Hmm....you don't need to do that.
Your class should have getQuantity()
. Just run the add()
and then do assert for getQuantity()
.
Anyway...you could mock setQuantity()
(for example) to throw exception.
Then assert that add
will throw the exception.
Maybe you could test with add(2)
, mock add
only for specific argument :)
Upvotes: 1