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

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

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

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

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

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

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

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

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

}

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

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

Кстати, это функции настройки для 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;
}

person Robert Austin    schedule 08.09.2014    source источник


Ответы (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');
    }

}

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

person Alexandre Butynski    schedule 08.09.2014
comment
Спасибо за ответ. У меня есть соблазн держаться подальше от Mockery, но что произойдет, если я создам базу данных, она работает нормально, переходит в производство и т.д., а затем пользователь сообщает об ошибке. Если я не имитирую и не запускаю какие-то тесты, не буду ли я вставлять и обновлять данные в фактической базе данных пользователей? - person Robert Austin; 08.09.2014
comment
Вы должны создать особую конфигурацию для вашей testing среды. Просто создайте app/config/testing/database.php файл с конфигурацией для другой базы данных, которая будет использоваться только тогда, когда вы будете запускать свои тесты. Прочтите документ, если вам нужны дополнительные сведения: laravel.com/docs/configuration#environment-configuration. - person Alexandre Butynski; 09.09.2014

Эта функция является частью проекта под названием 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;
}
person Mahmoud Zalt    schedule 28.03.2017