模拟 Laravel 模型不工作 - 无论如何都去数据库
Mocking a Laravel model not working - Goes for the database anyway
我目前正在尝试遵循存储库模式,我已经到了需要测试存储库的部分。我要测试的是调用 create 函数并在不实际访问数据库的情况下模拟结果。但是当 运行 测试时,我得到了错误:
PDOException: SQLSTATE[HY000] [2003] Can't connect to MySQL server on 'mysql' (113)
这是我的测试文件的样子:
<?php
class UserRepositoryTest extends TestCase
{
private $user;
public function __construct()
{
$this->mock = Mockery::mock('App\User');
$this->user = new \App\Repositories\UserRepository(new Illuminate\Container\Container, new \Illuminate\Support\Collection);
}
public function setUp()
{
parent::setUp();
}
public function tearDown()
{
Mockery::close();
}
public function testCreate()
{
$this->mock
->shouldReceive('create')
->withAnyArgs()
->once()
->andReturn(array());
$user = $this->user->create(['password' => 'secret']);
}
}
用户存储库如下所示:
<?php
namespace App\Repositories;
use App\Repositories\Eloquent\Repository;
use Illuminate\Support\Facades\Hash;
class UserRepository extends Repository
{
/**
* Specify Model class name.
*
* @return mixed
*/
public function model()
{
return 'App\User';
}
/**
* @param array $data
*
* @return mixed
*/
public function create(array $data)
{
$data['partner_status'] = 'Active';
$data['password'] = Hash::make($data['password']);
return parent::create($data);
}
}
父级的创建函数如下所示:
/**
* @param array $data
*
* @return mixed
*/
public function create(array $data)
{
return $this->model->create($data);
}
我如何模拟它,使其实际上 return 我告诉它什么 return?
您是否在 config/database.php
中设置了合适的测试环境?
举个例子:
'testing' => [
'driver' => 'mysql',
'host' => env('DB_TEST_HOST', 'localhost'),
'port' => env('DB_TEST_PORT', '3306'),
'database' => env('DB_TEST_DATABASE', 'homestead_test'),
'username' => env('DB_TEST_USERNAME', 'homestead'),
'password' => env('DB_TEST_PASSWORD', 'secret'),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
然后添加一个名为 homestead_test
的新数据库,添加一个名为 homestead
的用户并将通行证设置为 secret
。
编辑:没关系,我误读了你的问题。这对你一点帮助都没有。
模拟一个对象会创建一个特定的模拟实例。它不会影响创建该类型对象的新实例的任何其他代码。例如:
$mock = Mockery::mock('App\User');
$user = new \App\User();
在上面的例子中,$mock
将是模拟对象的一个实例,但 $user
仍然是一个普通的 User
对象,与模拟对象完全无关。
这个测试实际上是在引导您走向更好的设计之路。目前,您的 UserRepository
对 \App\User
class 有隐藏的依赖。要解决此问题,您应该将依赖项添加到存储库的构造函数中,以便在创建存储库时将其注入。
通过将依赖项添加到构造函数,它不再隐藏,您将能够注入您的模拟对象,而不是让存储库尝试创建新对象,这些对象更难测试,因为您发现了。
因此,您的存储库将类似于:
class UserRepository extends Repository
{
public function __construct(\App\User $model, \Illuminate\Container\Container $container, \Illuminate\Support\Collection $collection) {
$this->model = $model;
$this->container = $container;
$this->collection = $collection;
}
}
然后您的测试将类似于:
class UserRepositoryTest extends TestCase
{
public function __construct()
{
$this->mock = Mockery::mock('App\User');
}
public function testCreate()
{
$this->mock
->shouldReceive('create')
->withAnyArgs()
->once()
->andReturn(array());
$repo = new \App\Repositories\UserRepository($this->mock, new Illuminate\Container\Container, new \Illuminate\Support\Collection);
$user = $repo->create(['password' => 'secret']);
}
}
我目前正在尝试遵循存储库模式,我已经到了需要测试存储库的部分。我要测试的是调用 create 函数并在不实际访问数据库的情况下模拟结果。但是当 运行 测试时,我得到了错误:
PDOException: SQLSTATE[HY000] [2003] Can't connect to MySQL server on 'mysql' (113)
这是我的测试文件的样子:
<?php
class UserRepositoryTest extends TestCase
{
private $user;
public function __construct()
{
$this->mock = Mockery::mock('App\User');
$this->user = new \App\Repositories\UserRepository(new Illuminate\Container\Container, new \Illuminate\Support\Collection);
}
public function setUp()
{
parent::setUp();
}
public function tearDown()
{
Mockery::close();
}
public function testCreate()
{
$this->mock
->shouldReceive('create')
->withAnyArgs()
->once()
->andReturn(array());
$user = $this->user->create(['password' => 'secret']);
}
}
用户存储库如下所示:
<?php
namespace App\Repositories;
use App\Repositories\Eloquent\Repository;
use Illuminate\Support\Facades\Hash;
class UserRepository extends Repository
{
/**
* Specify Model class name.
*
* @return mixed
*/
public function model()
{
return 'App\User';
}
/**
* @param array $data
*
* @return mixed
*/
public function create(array $data)
{
$data['partner_status'] = 'Active';
$data['password'] = Hash::make($data['password']);
return parent::create($data);
}
}
父级的创建函数如下所示:
/**
* @param array $data
*
* @return mixed
*/
public function create(array $data)
{
return $this->model->create($data);
}
我如何模拟它,使其实际上 return 我告诉它什么 return?
您是否在 config/database.php
中设置了合适的测试环境?
举个例子:
'testing' => [
'driver' => 'mysql',
'host' => env('DB_TEST_HOST', 'localhost'),
'port' => env('DB_TEST_PORT', '3306'),
'database' => env('DB_TEST_DATABASE', 'homestead_test'),
'username' => env('DB_TEST_USERNAME', 'homestead'),
'password' => env('DB_TEST_PASSWORD', 'secret'),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
然后添加一个名为 homestead_test
的新数据库,添加一个名为 homestead
的用户并将通行证设置为 secret
。
编辑:没关系,我误读了你的问题。这对你一点帮助都没有。
模拟一个对象会创建一个特定的模拟实例。它不会影响创建该类型对象的新实例的任何其他代码。例如:
$mock = Mockery::mock('App\User');
$user = new \App\User();
在上面的例子中,$mock
将是模拟对象的一个实例,但 $user
仍然是一个普通的 User
对象,与模拟对象完全无关。
这个测试实际上是在引导您走向更好的设计之路。目前,您的 UserRepository
对 \App\User
class 有隐藏的依赖。要解决此问题,您应该将依赖项添加到存储库的构造函数中,以便在创建存储库时将其注入。
通过将依赖项添加到构造函数,它不再隐藏,您将能够注入您的模拟对象,而不是让存储库尝试创建新对象,这些对象更难测试,因为您发现了。
因此,您的存储库将类似于:
class UserRepository extends Repository
{
public function __construct(\App\User $model, \Illuminate\Container\Container $container, \Illuminate\Support\Collection $collection) {
$this->model = $model;
$this->container = $container;
$this->collection = $collection;
}
}
然后您的测试将类似于:
class UserRepositoryTest extends TestCase
{
public function __construct()
{
$this->mock = Mockery::mock('App\User');
}
public function testCreate()
{
$this->mock
->shouldReceive('create')
->withAnyArgs()
->once()
->andReturn(array());
$repo = new \App\Repositories\UserRepository($this->mock, new Illuminate\Container\Container, new \Illuminate\Support\Collection);
$user = $repo->create(['password' => 'secret']);
}
}