Как я могу издеваться над классом, который используется в ремесленной команде для тестирования? - PullRequest
0 голосов
/ 09 октября 2018

У меня есть команда ремесленника, которая вызывает другую функцию классов.Эта функция выполняет запрос get на другой сервер, и я не хочу, чтобы этот запрос get выполнялся во время тестирования.

Мое обычное решение состоит в том, чтобы смоделировать эту функцию с использованием насмешки, однако это не похоже на работу.

Почему мой макет не вызывается, когда я вызываю ремесленную команду, используя Artisan::call('command::getFoo')?

Класс команды

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Foo;

class GetFoo extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'command:getFoo';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Get the foo data';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {       
        return Foo::get();  // Returns true
    }
}

Класс тестирования

namespace Tests\Feature;

use Tests\TestCase;
use App\Foo;

class FooCommandTest extends TestCase 
{
    public function testThatWeCanGetFoo()
    {
        $fooClass = Mockery::mock(Foo::class);
        $fooClass->shouldReceive(['get' => false]); // Overwrite the foo class to return false instead of true
        $fooData = \Artisan::call('command:getFoo');

        $this->assertFalse($fooData);
    }
}

Когда явыполнить мой тест не удалось, потому что он все еще возвращаетсяЭто означает, что насмешливый класс не вызывается.Что здесь происходит?Как я могу проверить эту команду?

1 Ответ

0 голосов
/ 10 октября 2018

Вы можете попробовать создать фиктивного потомка корневого класса, который использует Artisan Facade, и переопределить любой метод, который выполняет нежелательные действия.А затем, в вашем тесте, позвоните Artisan::swap($dummyObj);, чтобы заменить его.

-

Это не очень хорошо задокументировано, я думаю, что столкнулся с этим, когда я искал детальный способразрешить запуск некоторых событий в моем тесте и запретить другим избегать побочных действий.Так что Illuminate\Support\Facades\Event::fake() является хорошим примером того, как это использовать.

Итак, заглянем под капот:

  • config/app.php определяет Artisan как указывающий на Illuminate\Support\Facades\Artisan.
  • Illuminate\Support\Facades\Artisan::getFacadeAccessor() определяет имя средства доступа к фасаду как имя интерфейса Illuminate\Contracts\Console\Kernel.
  • И интерфейс ядра привязан к одиночному элементу App \ Console \ Kernel в * 1021.*.

Все в сумме, это означает, что каждый раз, когда вы звоните по \Artisan, вы на самом деле говорите с повторно используемым экземпляром App\Console\Kernel.

App\Console\Kernel extends Illuminate\Foundation\Console\Kernel, и , что - это то, что обладало командой call(), для которой вы хотели бы управлять поведением.

Итак, вы хотите что-то вроде этого:

namespace Tests\Dummies;

use App\Console\Kernel as BaseKernel;

class Artisan extends BaseKernel
{
    // This will override the parent's call() and block it from doing anything.
    public function call($command, array $parameters = [], $outputBuffer = null)
    {
        // -- Do nothing instead, or add some debug logging here --
    }
}

Затем, в качестве первого действия внутри вашего теста или части метода setUp(), выполните:

$dummyArtisan = app(Tests\Dummies\Artisan::class);
Artisan::swap($dummyArtisan);

Обратите внимание, что все это не проверено.Я делал подобные вещи в прошлом и могу с уверенностью сказать, что теория солидна.Но я не знаю, является ли этот конкретный код.

-

Возможно, вы также захотите взглянуть на Illuminate\Support\Facades\Facade::spy() и Illuminate\Support\Facades\Facade::shouldReceive().Я просто заметил их, когда смотрел код здесь, чтобы написать этот ответ, и они заставляют меня задуматься, не изобрело ли мое предложение немного колесо заново.Похоже, что Фасады спроектированы с небольшим осознанием того, что их сложно издеваться, поэтому у них есть некоторые инструменты для этого.

...