The class under test is as follows:
class ElasticSearchInstaller
{
/**
* Version of ElasticSearch
*
* @var \ElasticSearch\Requierments
*/
protected $requirements;
/**
* Object Constructor.
*
* @param Requierments $requirements
*/
public function __construct(Requirements $requirements)
{
$this->requirements = $requirements;
}
/**
* Set requirements
*
* @return bool
*/
public function canInstall()
{
return ($this->isInstalled() && $this->requirements->checkRequirements());
}
}
The test looks as follows:
class ElasticSearchInstallerTest extends TestCase
{
/** @test **/
public function it_can_check_if_its_installable()
{
$requirements = m::mock('alias:ElasticSearch\Requirements');
$requirements->shouldReceive('checkRequirements')->once()->andReturn(true);
$installer = new ElasticSearchInstaller($requirements);
$this->assertInternalType('bool', $installer->canInstall());
}
}
Although for some reason it does not pass, as the mock says checkRequirements()
is not being called and expects to be called once.
1) ElasticSearchInstallerTest::it_can_check_if_its_installable
Mockery\Exception\InvalidCountException: Method checkRequirements() from App\ElasticSearch\Requirements should be called
exactly 1 times but called 0 times.
EDIT The problem was, within canInstall()
for some reason if $this->isInstalled()
is called before $this->requirements->checkRequirements()
such as in the code above. It errors. if its swapped to:
public function canInstall()
{
return ($this->requirements->checkRequirements() && $this->isInstalled() );
}
...it passes! wtf?
The issue is that such boolean conditions can be shortcut -if the first part of an &&
(and) condition is FALSE, the whoe condition itself cannot become true, and so the rest of the parts of the conditional is skipped. The function call was skipped, hence, run 0 times.
Since, in that specific test, you only only currently testing the condition as a whole, you can mock the rest of the ElasticSearchInstaller
and do much the same:
$searchInstaller->shouldReceive('isInstalled')->andReturn(true);
The mock would fall back to use the original canInstall(), and so run the condition. It's still almost a too-simple-to-fail case though - I'd concentrate elsewhere for testing.