Laravel 8 — класс не использует макет версии класса в тесте

#laravel #testing #mocking

Вопрос:

Привет, последний вопрос по разгадке кода — я пытаюсь создавать тесты, которые издеваются над определенными классами, но изо всех сил пытаюсь заставить свою первую попытку работать. Похоже, что в тесте используется не макет, а реальный класс.

Есть три вопроса:

  1. Что мне нужно изменить, чтобы заставить это работать и использовать макет?
  2. Работает ли макет для всего тестируемого приложения или только для тестируемого класса?
  3. Если бы я хотел вернуть массив значений, нужно ли мне просто создать массив с ожидаемыми значениями, чтобы тестируемый класс мог использовать эти возвращенные данные?

Итак, вот класс, над которым я хочу поиздеваться:

 <?php

namespace AppWedleagueUtility;

use AppLibrariesUtilitiesFolderUtility;
use AppWedleagueLeagueTableLeagueTableInterface;
use PDF;

/**
 * Class PDFGenerator
 * Generates a PDF based on a league
 * @package AppLibrariesHelpers
 */
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 BarryvdhDomPDFPDF
     */
    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);
    }
}
 

Вот класс, который я пытаюсь протестировать, который использует этот класс:

 <?php

namespace AppJobs;

use AppWedleagueUtilityPDFGenerator;
use AppMailMailEclecticUpdate;
use AppModelsLeague;
use AppWedleagueLeagueTableEclecticLeagueTable;
use Exception;
use IlluminateBusQueueable;
use IlluminateContractsQueueShouldQueue;
use IlluminateFoundationBusDispatchable;
use IlluminateQueueInteractsWithQueue;
use IlluminateQueueSerializesModels;
use IlluminateSupportFacadesLog;
use IlluminateSupportFacadesMail;

/**
 * Class ProcessSendEclecticUpdate
 * @package AppJobs
 */
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;

    private League $league;

    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 TestsJobs;

use AppJobsProcessSendEclecticUpdateEmail;
use AppMailMailEclecticUpdate;
use AppModelsLeague;
use AppModelsUser;
use AppWedleagueUtilityPDFGenerator;
use IlluminateFoundationTestingRefreshDatabase;
use IlluminateFoundationTestingWithFaker;
use IlluminateSupportFacadesBus;
use IlluminateSupportFacadesMail;
use TestsTestCase;

/**
 * Class ProcessSendEclecticUpdateTest
 * @package TestsJobs
 */
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(AppWedleagueUtilityPDFGenerator::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:

 MockeryExceptionInvalidCountException : 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!!! 🙂