Skip to content

Instantly share code, notes, and snippets.

@celyes
Created March 18, 2025 09:44
Show Gist options
  • Save celyes/78e3b83bc7c13ac1d730e0dc8b83f8e1 to your computer and use it in GitHub Desktop.
Save celyes/78e3b83bc7c13ac1d730e0dc8b83f8e1 to your computer and use it in GitHub Desktop.

Revisions

  1. celyes created this gist Mar 18, 2025.
    146 changes: 146 additions & 0 deletions task-3.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,146 @@
    <?php

    namespace Tests\Unit\Services;

    use App\Jobs\ProcessProductImage;
    use App\Models\Product;
    use App\Services\SpreadsheetService;
    use Illuminate\Support\Facades\Validator;
    use Illuminate\Support\Facades\Queue;
    use Mockery;
    use Tests\TestCase;

    class SpreadsheetServiceTest extends TestCase
    {
    protected function tearDown(): void
    {
    Mockery::close();
    parent::tearDown();
    }

    /**
    * @return array
    */
    public function spreadsheetDataProvider()
    {
    return [
    'valid data' => [
    [
    'product_code' => 'ABC123',
    'quantity' => 10,
    ],
    false, // Validation fails
    true, // Product creation
    true, // Job dispatched
    ],
    'missing product_code' => [
    [
    'quantity' => 10,
    ],
    true, // Validation fails
    false, // Product creation
    false, // Job dispatched
    ],
    'invalid quantity' => [
    [
    'product_code' => 'DEF456',
    'quantity' => 0,
    ],
    true, // Validation fails
    false, // Product creation
    false, // Job dispatched
    ],
    ];
    }

    /**
    * @dataProvider spreadsheetDataProvider
    */
    public function testProcessSpreadsheet($rowData, $validationFails, $productCreated, $jobDispatched)
    {
    $importerMock = $this->mockImporter($filePath = 'path/to/spreadsheet.xlsx', $rowData);
    $this->mockValidator($rowData, $validationFails);
    $this->mockProductCreation($rowData, $productCreated);

    Queue::fake();

    $service = new SpreadsheetService();
    $service->processSpreadsheet($filePath);
    $this->assertJobDispatch($rowData, $jobDispatched);
    }

    /**
    * @param string $filePath
    * @param array $rowData
    * @return \Mockery\MockInterface
    */
    protected function mockImporter(string $filePath, array $rowData)
    {
    $importerMock = Mockery::mock();
    $this->app->instance('importer', $importerMock);

    $importerMock->shouldReceive('import')
    ->once()
    ->with($filePath)
    ->andReturn([$rowData]);

    return $importerMock;
    }

    /**
    * @param array $rowData
    * @param bool $validationFails
    * @return void
    */
    protected function mockValidator(array $rowData, bool $validationFails)
    {
    $validatorMock = Mockery::mock();
    $validatorMock->shouldReceive('fails')
    ->andReturn($validationFails);
    $validatorMock->shouldReceive('validated')
    ->andReturn($rowData);

    Validator::shouldReceive('make')
    ->once()
    ->with($rowData, [
    'product_code' => 'required|unique:products,code',
    'quantity' => 'required|integer|min:1',
    ])
    ->andReturn($validatorMock);
    }

    /**
    * @param array $rowData
    * @param bool $productCreated
    * @return void
    */
    protected function mockProductCreation(array $rowData, bool $productCreated)
    {
    if ($productCreated) {
    $productMock = (object) $rowData;
    Product::shouldReceive('create')
    ->once()
    ->with($rowData)
    ->andReturn($productMock);
    } else {
    Product::shouldReceive('create')
    ->never();
    }
    }

    /**
    * @param array $rowData
    * @param bool $jobDispatched
    * @return void
    */
    protected function assertJobDispatch(array $rowData, bool $jobDispatched)
    {
    if ($jobDispatched) {
    Queue::assertPushed(ProcessProductImage::class, function ($job) use ($rowData) {
    return $job->product->product_code === $rowData['product_code'];
    });
    } else {
    Queue::assertNotPushed(ProcessProductImage::class);
    }
    }
    }