Jul 8, 2021
0
Level 4
Mocking woes: Mock class method not called in Laravel
Hi Latest question on unraveling code - I'm trying to create tests that mock certain classes but struggling to get my first attempt to work. It does not appear to be using the mock in the test but the real class.
There are three questions:
- What do I need to change to get this to work and the mock to be used?
- Does the mock work for the whole app under test or just the class under test?
- If I wanted to return an array of values do I just create the array with the expected values to enable the class under test to use that returned data?
So here's the class I want to mock:
<?php
namespace App\Wedleague\Utility;
use App\Libraries\Utilities\FolderUtility;
use App\Wedleague\LeagueTable\LeagueTableInterface;
use PDF;
/**
* Class PDFGenerator
* Generates a PDF based on a league
* @package App\Libraries\Helpers
*/
class PDFGenerator
{
use FolderUtility;
/**
* set the folder location for the generated pdf
* @var string
*/
private string $storageFolder = 'pdf';
private string $path;
private LeagueTableInterface $leagueTable;
/**
* PDFGenerator constructor.
*/
public function __construct(LeagueTableInterface $leagueTable)
{
$this->path = storage_path('app/' . $this->storageFolder);
$this->setUp();
$this->leagueTable = $leagueTable;
}
/**
* @return \Barryvdh\DomPDF\PDF
*/
public function createLeaguePDF()
{
$this->leagueTable->getLeagueTable();
error_reporting(E_ALL ^ E_DEPRECATED);
return PDF::loadView($this->leagueTable->getViewPath(), $this->leagueTable->getViewData())
->setOptions(['fontSubsetting' => true])
->setPaper('a4', 'landscape')
->save(storage_path('app/pdf/' . $this->leagueTable->getLeagueType() . '_league_update.pdf'));
}
private function setUp()
{
$this->checkFolderExists($this->path);
}
}
Here's the class I'm trying to test that uses this class:
<?php
namespace App\Jobs;
use App\Wedleague\Utility\PDFGenerator;
use App\Libraries\Repositories\LeagueRepository;
use App\Mail\MailEclecticUpdate;
use App\Models\League;
use App\Wedleague\LeagueTable\EclecticLeagueTable;
use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
/**
* Class ProcessSendEclecticUpdate
* @package App\Jobs
*/
class ProcessSendEclecticUpdateEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* The number of times the job may be attempted.
*
* @var int
*/
public $tries = 3;
/**
* The number of seconds the job can run before timing out.
*
* @var int
*/
public $timeout = 240;
/**
* @var LeagueRepository
*/
private $leagueRepository;
private League $league;
/**
* Create a new job instance.
*
* @param LeagueRepository $leagueRepository
*/
public function __construct(League $league)
{
$this->league = $league;
}
public function handle()
{
if (!$this->league || $this->league->league_type !== 'eclectic') {
throw new Exception("Error Processing the job - league not found or invalid league", 1);
}
$PDFGenerator = new PDFGenerator(new EclecticLeagueTable($this->league));
$PDFGenerator->createLeaguePDF();
$this->league->player()->get()->each(function ($player) {
if ($player->contactEmail) {
Mail::to($player->contactEmail)
->queue(new MailEclecticUpdate(
$this->league
));
}
});
Log::info('Eclectic League update issued');
}
}
and here's the basics of the test:
<?php
namespace Tests\Jobs;
use App\Jobs\ProcessSendEclecticUpdateEmail;
use App\Mail\MailEclecticUpdate;
use App\Models\League;
use App\Models\User;
use App\Wedleague\Utility\PDFGenerator;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Mail;
use Tests\TestCase;
/**
* Class ProcessSendEclecticUpdateTest
* @package Tests\Jobs
*/
class ProcessSendEclecticUpdateTest extends TestCase
{
use RefreshDatabase;
use WithFaker;
private $user;
private $adminUser;
protected function setUp(): void
{
parent::setUp();
$this->seed();
$this->adminUser = User::factory()->create(['admin' => 1]);
}
/**
* @test
* @covers ProcessSendEclecticUpdateEmail::handle
* @description:
*/
public function testHandle()
{
$mock = $this->mock(\App\Wedleague\Utility\PDFGenerator::class);
$mock->shouldReceive('createLeaguePDF')->once();
$this->app->instance(PDFGenerator::class, $mock);
Mail::fake();
$this->withoutExceptionHandling();
$league = League::find(27);
$players = $league->player()
->get()
->filter(function ($player){
return $player->contactEmail;
});
ProcessSendEclecticUpdateEmail::dispatch($league);
Mail::assertQueued(MailEclecticUpdate::class, $players->count());
}
}
The response I get from the test is:
Mockery\Exception\InvalidCountException : Method createLeaguePDF(<Any Arguments>) from Mockery_2_App_Wedleague_Utility_PDFGenerator should be called
exactly 1 times but called 0 times.
I know this is not using the mock due to the length of time the test takes as it produces a PDF
Any ideas how I can get this to work - it's mocking me!!! :)
Please or to participate in this conversation.