使用 PHP 嘲笑模拟具体 class 时出错

Error mocking concrete class with PHP mockery

测试的class如下:

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());
    }   
}

测试结果如下:

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());
    }    
}

虽然由于某种原因它没有通过,正如模拟所说 checkRequirements() 没有被调用并且期望被调用一次。

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.

编辑 问题是,如果 $this->isInstalled()$this->requirements->checkRequirements() 之前调用,由于某种原因,在 canInstall() 中,例如上面的代码。它出错了。如果它换成:

public function canInstall() 
{
    return ($this->requirements->checkRequirements() && $this->isInstalled() );
}  

...它通过了!卧槽?

问题是这样的布尔条件可以是快捷方式——如果 &&(和)条件的第一部分为 FALSE,则 whoe 条件本身不能变为真,因此其余部分条件被跳过。函数调用被跳过,因此 运行 0 次。

因为在那个特定的测试中,您目前只测试整个条件,您可以模拟 ElasticSearchInstaller 的其余部分并做同样的事情:

$searchInstaller->shouldReceive('isInstalled')->andReturn(true); 

模拟将退回到使用原始的 canInstall(),因此 运行 条件。尽管如此,它仍然几乎是一个过于简单而不会失败的案例 - 我会集中精力在其他地方进行测试。