【问题标题】:Testing a method that clones a mocked parameter测试克隆模拟参数的方法
【发布时间】:2018-01-19 07:10:08
【问题描述】:

我有一个类 getPaginatedQuery,它的第一步会立即克隆它的一个参数:

public function getPaginatedQuery(Builder $query, $limit = null, $offset = null)
{
    $constrainedQuery = clone $query;
    ...
}

Builder 对象的克隆是通过其__clone 魔术方法完成的。

我正在尝试通过为$query 传递一个模拟的Builder 实例来对该方法进行单元测试:

$query = m::mock('Illuminate\Database\Eloquent\Builder');
$relation->getPaginatedQuery($query, 2, 1);

我的测试因致命错误而失败:__clone method called on non-object。我尝试在我的 $query 对象上定义对 __clone 的期望,但我得到了同样的错误:

$query = m::mock('Illuminate\Database\Eloquent\Builder');        
$clonedQuery = m::mock('Illuminate\Database\Eloquent\Builder');
$query->shouldReceive('__clone')->andReturn($clonedQuery);

$relation->getPaginatedQuery($query, 2, 1);

我在这里做错了什么?

【问题讨论】:

    标签: php unit-testing mocking clone mockery


    【解决方案1】:

    Eloquent\Builder 实际上包含(作为成员)Query\Builder 的一个实例,其神奇的__clone 方法在这个底层Query\Builder 对象上调用clone

    /**
     * Force a clone of the underlying query builder when cloning.
     *
     * @return void
     */
    public function __clone()
    {
        $this->query = clone $this->query;
    }
    

    由于您在模拟 Eloquent\Builder,它实际上并没有底层的 $this->query 成员,因为它将在 Eloquent\Builder 的构造函数中设置,而该构造函数永远不会在完全模拟的对象中被调用。

    要解决这个问题,您需要创建一个 Eloquent\Builder 的部分模拟,并使用 Query\Builder 的模拟实例告诉 run its real constructor

    $baseQuery = m::mock('Illuminate\Database\Query\Builder');
    $query = m::mock('Illuminate\Database\Eloquent\Builder', [$baseQuery])->makePartial();
    
    $relation->getPaginatedQuery($query, 2, 1);
    

    现在,当在 getPaginatedQuery() 中调用 clone $query 时,模拟的 Eloquent\Builder 实例将能够在 模拟的 Query\Builder 实例上调用 clone

    【讨论】:

      猜你喜欢
      • 2022-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-05
      • 1970-01-01
      • 2016-07-20
      • 1970-01-01
      相关资源
      最近更新 更多