Laravel Test | Mock object in Laravel Artisan Command

独自空忆成欢 提交于 2019-12-12 15:17:14

问题


I want to test my Laravel Artisan command. So I need to mock an object and stubs this mocked object methods. In my test, I cannot use the real SFTP environment.

This is the handle() of my command:

public function handle()
{
   $sftp = new SFTP('my.sftpenv.com');
   $sftp->login('foo', 'bar');
}

I want to mock the SFTP in my test:

$sftp = $this->createMock(SFTP::class);
$sftp->expects($this->any())->method('login')->with('foo', 'bar');
$this->artisan('import:foo');

Running the test results in a Cannot connect to ...:22, which comes from the original login method of SFTP. So the mock/stub does not take effect.

So my question is: how can I mock an object in a Laravel Artisan command test?


回答1:


I think what @Mesuti means is that if you bind your SFTP object to your service container you would be able to swap it out with a mock object when running your test.

You could bind it like this (either inside your app/Providers/AppServiceProvider.php or a new service provider):

$this->app->singleton(SFTP::class, function ($app) {
            return new SFTP('my.sftpenv.com');
        });

You could then resolve the object in your command's handler (e.g. $sftp = resolve('SFTP');) and then mock it inside your test like this:

$this->mock(SFTP::class, function ($mock) {
    $mock->expects()->login('foo', 'bar')->andReturn('whatever you want it to return');
});

Just a note for future readers that service you are mocking should be resolved in the handle method of the command and not in the __construct method like you would often do in other circumstances. It seems like the artisan commands are resolved before the tests are run so if you resolve the service in the constructor of the command, it wouldn't resolve to the mocked instance.



来源:https://stackoverflow.com/questions/56853267/laravel-test-mock-object-in-laravel-artisan-command

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!