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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With