Издевательство над Laravel

Я пытаюсь настроить самые простые тесты в моем контроллере, но, как и в большинстве случаев с Laravel, не существует достойных руководств для демонстрации простых вещей.

Я могу запустить простой тест (в файле с именем UserControllerTest), например:

public function testIndex()
{      
    $this->call('GET', 'users');
    $this->assertViewHas('users');
}

Это вызывает маршрут /users и передает массив users.

Я хочу сделать то же самое с издевательством, но как?

Если я попробую это:

public function testIndex()
{
  $this->mock->shouldReceive('users')->once();

  $this->call('GET', 'users');

}

Я получаю сообщение об ошибке, что "Статический метод Mockery_0_users::all не существует в этом фиктивном объекте.

Почему бы и нет? Я издеваюсь над пользователем, который расширяет Ardent и, в свою очередь, расширяет Eloquent. Почему:: все не существует для макета?

Кстати, это функции настройки для Mockery:

public function setUp()
{
  parent::setUp();

  $this->mock = $this->mock('User');
}

public function mock($class)
{
  $mock = Mockery::mock($class);

  $this->app->instance($class, $mock);

  return $mock;
}

2 ответа

Решение

Вы не можете напрямую издеваться над классом Eloquent. Eloquent не является ни Фасадом, ни вашей моделью пользователя. В Laravel есть немного магии, но вы не можете делать такие вещи.

Если вы хотите смоделировать свой класс User, вы должны внедрить его в конструктор контроллера. Шаблон репозитория является хорошим подходом, если вы хотите это сделать. Есть много статей об этом шаблоне и Laravel в Google.

Вот несколько фрагментов кода, чтобы показать вам, как это может выглядеть:

class UserController extends BaseController {

    public function __construct(UserRepositoryInterface $users)
    {
        $this->users = $users;
    }

    public function index()
    {
        $users = $this->users->all();
        return View::make('user.index', compact('users'));
    }

}

class UserControllerTest extends TestCase
{

    public function testIndex()
    {
        $repository = m::mock('UserRepositoryInterface');
        $repository->shouldReceive('all')->andReturn(new Collection(array(new User, new User)));
        App::instance('UserRepositoryInterface', $repository);

        $this->call('GET', 'users');
    }

}

Если вам кажется, что для вашего проекта слишком много структурирования, вы можете просто вызвать реальную базу данных в своих тестах и ​​не издеваться над классами моделей... В классическом проекте это просто отлично работает.

Эта функция является частью проекта под названием apiato.io Вы можете использовать его для макетирования любого класса в Laravel, даже фасадного, в основном всего, что может быть разрешено с помощью IoC, а это почти все классы, если вы используете правильное внедрение зависимостей:

/**
 * Mocking helper
 *
 * @param $class
 *
 * @return  \Mockery\MockInterface
 */
public function mock($class)
{
    $mock = Mockery::mock($class);
    App::instance($class, $mock);

    return $mock;
}
Другие вопросы по тегам