Joh*_*sey 8 php testing phpunit mocking laravel
Laravel 5.8 中是否可以模拟或伪造模型方法的输出?
例如,考虑这个模型
class Website extends Model
{
public function checkDomainConfiguration($domain): bool
{
try {
$records = dns_get_record($domain, DNS_A);
} catch (ErrorException $e) {
return false;
}
if (isset($records[0]['ip']) && $records[0]['ip'] === $this->server->ipv4_address) {
return true;
}
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
出于测试的目的,我需要告诉 phpunit,当此方法触发时(在控制器中调用),返回 true,如果我故意希望它失败,则返回 false。在测试中我工厂创建了一个网站,当然它会通过php方法失败dns_get_record
。
我已经阅读了 Laravel 文档,并在 google 上搜索了有关模拟模型方法的信息,但似乎找不到任何内容,除了在if
方法周围封装一个大的内容来检查我是否处于测试模式,以及我是否只是返回真的。<-- 好极了。
更新这是我如何在控制器中调用方法的示例
class SomeController extends Controller
{
public function store(Website $website, Domain $domain)
{
if (! $website->checkDomainConfiguration($domain->domain)) {
return response([
'error' => 'error message'
], 500);
}
// continue on here if all good.
}
}
Run Code Online (Sandbox Code Playgroud)
这是测试中的一些代码
$website = factory(Website::class)->create();
$domain = factory(Domain::class)->create([
'website_id' => $website->id
]);
//Mock the website object
$websiteMock = \Mockery::mock(Website::class)->makePartial();
$websiteMock->shouldReceive('getAttribute')
->once()
->with('domain')
->andReturn($website->domain);
$websiteMock->shouldReceive('checkDomainConfiguration')
->with($domain->domain)
->andReturn(true);
app()->instance(Website::class, $websiteMock);
// tried end point like this
$response = $this->json(
'POST',
'api/my-end-point/websites/' . $website->domain . '/domain/' . $domain->id
);
//also tried like this
$response = $this->json(
'POST',
'api/my-end-point/websites/' . $websiteMock->domain . '/domain/' . $domain->id
);
Run Code Online (Sandbox Code Playgroud)
控制器方法接受网站和域模型绑定。如果我dd(get_class($website))
位于控制器的顶部,它会显示实际模型的命名空间,而不是模拟模型。
在代码中,您将模型作为参数注入到控制器中,这意味着 Laravel 的 ioc 将被要求提供模型的实例Website
,并在执行实际代码时提供它。
在您的测试中,您可以创建一个模拟,然后告诉国际奥委会在请求类似实例时返回该模拟Website
:
$websiteMock = Mockery::mock(Website::class);
app()->instance(Website::class, $websitemock)
Run Code Online (Sandbox Code Playgroud)
在执行你的控制器之前。现在,当在测试中执行控制器时,模拟将接收方法调用,您可以将其设置为期望它们并伪造响应。具体来说,在您的代码中,您的模拟应该预期并伪造两个调用,例如:
$websiteMock->shouldReceive('getAttribute')
->once()
->with('domain')
->andReturn('test.domain'):
$websiteMock->shouldReceive('checkDomainConfiguration')
->once()
->with('test.domain')
->andReturn(false):
Run Code Online (Sandbox Code Playgroud)
使用整个代码进行编辑(我编写了一些不重要的内容,例如路由或控制器名称,请使用您自己的)。
控制器
<?php
namespace App\Http\Controllers;
use App\Domain;
use App\Website;
class StackOverflowController extends Controller
{
public function store(Website $website, Domain $domain)
{
if (! $website->checkDomainConfiguration($domain->domain)) {
return response([
'error' => 'error message'
], 500);
}
}
}
Run Code Online (Sandbox Code Playgroud)
集成测试
public function testStackOverflow()
{
$website = Mockery::mock(Website::class);
app()->instance(Website::class, $website);
$domain = Mockery::mock(Domain::class);
app()->instance(Domain::class, $domain);
$domain->shouldReceive('getAttribute')
->once()
->with('domain')
->andReturn('some.domain');
$website->shouldReceive('checkDomainConfiguration')
->once()
->with('some.domain')
->andReturn(false);
$response = $this->json('POST', '/stack/websiteId/overflow/domainId');
$this->assertEquals('error message', json_decode($response->getContent())->error);
$this->assertEquals(500, $response->status());
}
Run Code Online (Sandbox Code Playgroud)
另外,我没有包含集成测试文件的开头,但请仔细检查您是否包含:
use App\Domain;
use App\Website;
Run Code Online (Sandbox Code Playgroud)