2015-09-16 34 views
1

我现在被困在Laravel 4.2中(与phpunit和嘲笑),但同样应该适用于更高版本。在Laravel中,模拟一个模型的雄辩查询

我有一个知识库用于我的FxRate模型。它有一个方法来获得的外汇汇率VS GBP包含此雄辩电话:

$query = \FxRate::where('currency', $currency) 
    ->where('fx_date', $fxDate->format('Y-m-d')) 
    ->first(); 

return $query->rate_to_gbp; 

在我的单元测试,我想嘲笑这个电话,所以我可以定义将通过此调用返回的查询结果而不是依靠数据库来实现其中的价值。

我的尝试是这样的:

$mocked_query_result = (object) ['rate_to_gbp' => 1.5]; 

FxRate::shouldReceive('where') 
     ->once() 
     ->andReturn($mocked_query_result); 

但我相当肯定这不会是最初的静态调用FxRate应该返回接受进一步where()调用和first()一些查询对象工作。

有没有嘲笑他的干净的方式?

回答

1

你应该通过你的模型的实例进仓库的构造:

public function __construct(FXRate $model) 
{ 
    $this->model = $model; 
} 

然后将查询变为:

$query = $this->model->where('currency', $currency)...etc 

然后你传递一个嘲笑模型回购当实例它:

$mockModel = Mockery::mock('FXRate'); 
// This could be better, and you should use correct with() calls but hey, it's only an example 
$mockModel->shouldReceive('where') 
    ->twice() 
    ->andReturn($mockModel); 
$mockModel->shouldReceive('first') 
    ->once() 
    ->andReturn($mocked_query_result); 
$repo = new Repo($mockModel) 
$this->assertEquals($mocked_query_result, $repo->testableMethod()); 

进一步编辑下面的评论。你可以返回任何模型的模拟,但我觉得嘲弄真实模型与可读性帮助:

$mockFXRate = Mockery::mock('FXRate'); 
$mockFXRate->shouldReceive('where') 
    ->once() 
    ->andReturn($mockFXRate); 
$mockFXRate->shouldReceive('first') 
    ->once() 
    ->andReturn($mocked_query_result); 
FXRate::shouldReceive('where') 
    ->andReturn($mockFXRate); 
+0

[该文档(http://laravel.com/docs/4.2/testing#mocking-facades)说这是可能嘲笑门面;这不是问题 - 我很高兴在这种情况下使用外观。难度是链式方法,看起来好像我需要为链中的每个方法返回一个新的模拟对象。 – harryg

+0

@harryg - 找到了你。我在编辑中采取了这种方法。也许不是最好的,所以有人可能会提出其他建议。有一个Mockery :: self()对象返回,但我有问题让它工作,从来没有坚持下去,所以值得一看。 – markdwhite

+0

嗯,我真不知道该作品为'FxRate ::其中(...)'不返回FxRate'的'一个实例;它返回一个'Illuminate \ Database \ Eloquent \ Builder'实例,它接受进一步链接的方法。 'first()'然后返回结果。 – harryg