Ad

Mocking A Laravel Command Dependency

- 1 answer

As the official Laravel's documentation says so I made the following command:

namespace App\Console\Commands;

use App\Model\Report;
use Illuminate\Console\Command;
use Exception;

class ExportAnualReport extends Command
{
    /**
     * @var string
     */
    protected $description = "Print Anual Report";

    /**
     * @var string
     */
    protected $signature = "report:anual";

    public function __construct()
    {
        parent::__construct();
    }

    public function handle(Report $report): int
    {
        //@todo Implement Upload
        try {
            $reportData = $report->getAnualReport();
            $this->table($reportData['headers'], $reportData['data']);
            return 0;
        } catch (Exception $e) {
            $this->error($e->getMessage());
            return 1;
        }
    }
}

But instead of the approach used in this question I already follow laravel's approach and recommendation and I utilize Dependency Injection in order to insert my model as a Service.

So I the meantime I thought it would be a good Idea to Unit test it:

namespace Tests\Command;

use App\Model\Report;
use Tests\TestCase;

class TripAdvisorUploadFeedCommandTest extends TestCase
{
    public function setUp()
    {
        parent::setUp();
    }

    public function testFailAnualReport()
    {
        $this->artisan('report:anual')->assertExitCode(1);
    }

    public function testSucessAnualReport()
    {
        $this->artisan('report:anual')->assertExitCode(0);
    }
}

But In my case I already have inject the Eloquent Model Report into my command via the handle function, so I want to mock the Report object instance Instead of hitting the actual database.

For the record the Report Object is the following:

namespace App\Model

use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon
use Illuminate\Database\Eloquent\ModelNotFoundException;

class Report extends Model
{
     /**
     * @var string
     */
    protected $table = 'myapp_report_records';

    /**
     * @var string
     */
    protected $primaryKey = 'report_id';

    public function getAnualReport()
    {
        $now=Carbon::now();
        $oneYearBefore=new Carbon($now);
        $oneYearBefore->modify('-1 year');

        $results=$this->where('date','>',$oneYearBefore)->where('date','<',$now)->all();

        if(empty($results)){
            throw new ModelNotFoundException();
        }

        return $results;
    }
}

So how I can mock the provided Report model?

Ad

Answer

First of all you need to create a mock of your model report class then you need to bind it to the container. this way whenever you call the report model class in your command class you'll have a mocked model class with the specific response that you are expecting.

$this->app->instance(Report::class, \Mockery::mock(Report::class, function($mock){
            $mock->shouldReceive('getAnualReport')->andReturn(['headers'=>'any values', 'data'=>'any values']);
        }));
Ad
source: stackoverflow.com
Ad