Reputation: 100
I'm currently trying to follow the repository pattern and I've gotten to the part where I need to test the repositories. What I'm trying to test is calling the create function and mocking the result without actually hitting the database. But when running the test, I end up with the error:
PDOException: SQLSTATE[HY000] [2003] Can't connect to MySQL server on 'mysql' (113)
Here's what my test file looks like:
<?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']);
}
}
Here's what the user repository looks like:
<?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);
}
}
And the parent's create function looks like this:
/**
* @param array $data
*
* @return mixed
*/
public function create(array $data)
{
return $this->model->create($data);
}
How do I mock it so it actually return what I tell it to return?
Upvotes: 3
Views: 3260
Reputation: 62238
Mocking an object creates one specific mocked instance. It does not affect any other code that creates new instances of that type of object. For example:
$mock = Mockery::mock('App\User');
$user = new \App\User();
In the above example, $mock
will be an instance of your mocked object, but $user
will still be a normal User
object, not related to the mock at all.
This test is actually leading you down the path to a better design. Currently, your UserRepository
has a hidden dependency on the \App\User
class. To tackle this issue, you should add the dependency to the constructor of your repository, so it can be injected when the repository is created.
By adding the dependency to the constructor, it is no longer hidden, and you will be able to inject your mocked object, instead of having the repository attempt to create new objects, which are more difficult to test, as you've found out.
So, your repository will look something like:
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;
}
}
And then your test would look something like:
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']);
}
}
Upvotes: 4
Reputation: 4135
Have you set a proper Testing environment in your config/database.php
?
Take something like this for example:
'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,
],
Then add a new database called homestead_test
, add a user called homestead
and set the pass to secret
.
EDIT: Nevermind, I misread your question. This won't help you at all.
Upvotes: 0