Насмешка над моделью Laravel не работает - все равно идет за базой данных

В настоящее время я пытаюсь следовать шаблону репозитория и попал в ту часть, где мне нужно протестировать репозитории. То, что я пытаюсь проверить, - это вызвать функцию 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);
}

Как мне посмеяться над тем, чтобы он действительно возвращал то, что я говорю, чтобы он вернулся?

2 ответа

Решение

Насмешка над объектом создает один конкретный оскверненный экземпляр. Это не влияет на любой другой код, который создает новые экземпляры этого типа объекта. Например:

$mock = Mockery::mock('App\User');
$user = new \App\User();

В приведенном выше примере $mock будет экземпляром вашего издевательского объекта, но $user все равно будет нормальным User объект, не связанный с макетом вообще.

Этот тест на самом деле ведет вас к лучшему дизайну. В настоящее время ваш UserRepository имеет скрытую зависимость от \App\User учебный класс. Чтобы решить эту проблему, вы должны добавить зависимость в конструктор вашего хранилища, чтобы ее можно было внедрить при создании хранилища.

Добавив зависимость в конструктор, она больше не будет скрыта, и вы сможете внедрить свой смоделированный объект вместо попытки создания новых объектов в хранилище, которые, как вы выяснили, труднее тестировать.

Итак, ваш репозиторий будет выглядеть примерно так:

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']);
    }
}

Вы установили правильную среду тестирования в своем 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,

РЕДАКТИРОВАТЬ: Неважно, я неправильно понял ваш вопрос. Это не поможет вам вообще.

Другие вопросы по тегам