Laravel 5.4 PHPunit 模型模拟
Laravel 5.4 Model mock for PHPunit
这是我第一次使用 Mockery for PHPUnit。我遵循了这个论坛中的示例,但仍然收到此错误:
Mockery\Exception\InvalidCountException: Method all() from
Mockery_0_App_Card should be called exactly 1 times but called 0
times.
基本上,我是在我的控制器中注入我的模型。像这样:
class CardController extends Controller
{
protected $repository;
function __construct(Model $repository)
{
$this->repository = $repository;
}
public function index()
{
$data = $this->repository->all();
return $data;
}
}
并尝试像这样进行测试:
class CardTest extends TestCase
{
protected $mock;
protected function setUp(): void
{
parent::setUp();
$this->mock = Mockery::mock('Model', '\App\Card');
}
public function testCardsList()
{
$this->mock->shouldReceive('all')
->once()
->andReturn(json_encode([[
"id"=> 1,
"name"=> "Aut modi quasi corrupti.",
"content"=> "..."
],
[
"id"=> 2,
"name"=> "Voluptas quia distinctio.",
"content"=> "..."
]]));
$this->app->instance('\App\Card', $this->mock);
$response = $this->json('GET', $this->api.'/cards');
$this->assertEquals(200, $response->status(), 'Response code must be 200');
}
}
我已经尝试了几个变体,但它总是一样的。比如,在控制器中设置 Mockery 或使用 Card::class 表示法。有什么线索吗?
此外,我确定响应是从数据库中提取数据,而不是使用我提供的数组。所以,Mockery 对我的模型没有任何影响。
经过一些阅读,我确信使用 SQLite 数据库进行测试比为模型创建模型要好得多。您不必做那么多工作来创建模型。我链接到一些关于如何实现测试环境的讨论线程,但我也粘贴了我最终编写的代码。
基本上,您必须将数据库配置为 SQLite。你会声明它将 运行 在内存中。这比使用文件快得多。
然后,您想要 运行 您的 迁移 。在我的例子中,还有 种子 数据库。
<?php
namespace Tests;
use DirectoryIterator;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Config;
abstract class TestCase extends BaseTestCase
{
use CreatesApplication;
protected function setUp()
{
parent::setUp();
Config::set('database.connections.sqlite.database', ':memory:');
Config::set('database.default', 'sqlite');
Artisan::call('migrate');
Artisan::call('db:seed');
protected function tearDown()
{
Artisan::call('migrate:reset');
parent::tearDown();
}
}
有一个警告:每个测试调用一次 setUp()
。而且我发现这种表示法不起作用,因为每次都会重新生成数据库:
@depends testCreateCard
我使用该表示法将 ID 从 testCreate()
传递给其他几种方法。但最终信任我的种子并使用硬编码值。
参考文献:
- Laravel 5 - Using Mockery to mock Eloquent model
- https://www.patrickstephan.me/post/setting-up-a-laravel-5-test-database.html
- https://laracasts.com/discuss/channels/testing/how-to-specify-a-testing-database-in-laravel-5
- https://laracasts.com/discuss/channels/general-discussion/how-to-migrate-a-testing-database-in-laravel-5
这是我第一次使用 Mockery for PHPUnit。我遵循了这个论坛中的示例,但仍然收到此错误:
Mockery\Exception\InvalidCountException: Method all() from Mockery_0_App_Card should be called exactly 1 times but called 0 times.
基本上,我是在我的控制器中注入我的模型。像这样:
class CardController extends Controller
{
protected $repository;
function __construct(Model $repository)
{
$this->repository = $repository;
}
public function index()
{
$data = $this->repository->all();
return $data;
}
}
并尝试像这样进行测试:
class CardTest extends TestCase
{
protected $mock;
protected function setUp(): void
{
parent::setUp();
$this->mock = Mockery::mock('Model', '\App\Card');
}
public function testCardsList()
{
$this->mock->shouldReceive('all')
->once()
->andReturn(json_encode([[
"id"=> 1,
"name"=> "Aut modi quasi corrupti.",
"content"=> "..."
],
[
"id"=> 2,
"name"=> "Voluptas quia distinctio.",
"content"=> "..."
]]));
$this->app->instance('\App\Card', $this->mock);
$response = $this->json('GET', $this->api.'/cards');
$this->assertEquals(200, $response->status(), 'Response code must be 200');
}
}
我已经尝试了几个变体,但它总是一样的。比如,在控制器中设置 Mockery 或使用 Card::class 表示法。有什么线索吗?
此外,我确定响应是从数据库中提取数据,而不是使用我提供的数组。所以,Mockery 对我的模型没有任何影响。
经过一些阅读,我确信使用 SQLite 数据库进行测试比为模型创建模型要好得多。您不必做那么多工作来创建模型。我链接到一些关于如何实现测试环境的讨论线程,但我也粘贴了我最终编写的代码。
基本上,您必须将数据库配置为 SQLite。你会声明它将 运行 在内存中。这比使用文件快得多。
然后,您想要 运行 您的 迁移 。在我的例子中,还有 种子 数据库。
<?php
namespace Tests;
use DirectoryIterator;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Config;
abstract class TestCase extends BaseTestCase
{
use CreatesApplication;
protected function setUp()
{
parent::setUp();
Config::set('database.connections.sqlite.database', ':memory:');
Config::set('database.default', 'sqlite');
Artisan::call('migrate');
Artisan::call('db:seed');
protected function tearDown()
{
Artisan::call('migrate:reset');
parent::tearDown();
}
}
有一个警告:每个测试调用一次 setUp()
。而且我发现这种表示法不起作用,因为每次都会重新生成数据库:
@depends testCreateCard
我使用该表示法将 ID 从 testCreate()
传递给其他几种方法。但最终信任我的种子并使用硬编码值。
参考文献:
- Laravel 5 - Using Mockery to mock Eloquent model
- https://www.patrickstephan.me/post/setting-up-a-laravel-5-test-database.html
- https://laracasts.com/discuss/channels/testing/how-to-specify-a-testing-database-in-laravel-5
- https://laracasts.com/discuss/channels/general-discussion/how-to-migrate-a-testing-database-in-laravel-5