ldc-arcadia-api/tests/Unit/Shared/DDD/Usecase/Builder/UsecaseBuilderTest.php
Jérémy Munsch 9c2c109d51 feat(usecase): add Transactional interface and update use cases
- Implemented Transactional interface for use cases requiring database transactions.
- Updated CreateClient, RegenerateClientSecret, and SetClientStatus to implement Transactional.
- Modified LaravelExecutor to handle transactional use cases appropriately.
- Enhanced tests for LaravelExecutor to cover transactional behavior.
2026-08-21 09:38:29 +02:00

185 lines
5.3 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Unit\Shared\DDD\Usecase\Builder;
use LogicException;
use Shared\DDD\Usecase\Builder\UsecaseBuilder;
use Shared\DDD\Usecase\Builder\UsecaseExecutionBuilder;
use Shared\DDD\Usecase\Builder\UsecaseExecutor;
use Shared\DDD\Usecase\Input;
use Shared\DDD\Usecase\Output;
use Shared\DDD\Usecase\Presenter;
use Shared\DDD\Usecase\Usecase;
covers(
UsecaseBuilder::class,
UsecaseExecutionBuilder::class
);
describe('UsecaseBuilder Unit Tests', function (): void {
it('successfully builds and executes a use case using fluent syntax with presenter', function (): void {
// GIVEN
$inputMock = new class () implements Input
{
};
$outputMock = new class () implements Output
{
};
$viewResult = new \stdClass();
$viewResult->success = true;
$usecaseMock = new class ($outputMock) implements Usecase
{
public function __construct(private readonly Output $output)
{
}
public function execute(Input $input): Output
{
return $this->output;
}
};
$presenterMock = new class ($viewResult) implements Presenter
{
public function __construct(private readonly object $view)
{
}
public function present(Output $output): object
{
return $this->view;
}
};
$executorMock = new class ($viewResult) implements UsecaseExecutor
{
public function __construct(private readonly object $view)
{
}
public function execute(Usecase $usecase, Input $input, ?Presenter $presenter = null): object
{
$output = $usecase->execute($input);
return $presenter?->present($output) ?? $output;
}
};
// WHEN
$result = UsecaseBuilder::using($executorMock)
->do($usecaseMock)
->from($inputMock)
->with($presenterMock)
->run();
// THEN
expect($result)->toBe($viewResult);
});
it('successfully builds and executes a use case without presenter returning Output directly', function (): void {
// GIVEN
$inputMock = new class () implements Input
{
};
$outputMock = new class () implements Output
{
};
$usecaseMock = new class ($outputMock) implements Usecase
{
public function __construct(private readonly Output $output)
{
}
public function execute(Input $input): Output
{
return $this->output;
}
};
$executorMock = new class () implements UsecaseExecutor
{
public function execute(Usecase $usecase, Input $input, ?Presenter $presenter = null): object
{
$output = $usecase->execute($input);
return $presenter?->present($output) ?? $output;
}
};
// WHEN
$result = UsecaseBuilder::using($executorMock)
->do($usecaseMock)
->from($inputMock)
->run();
// THEN
expect($result)->toBe($outputMock);
});
it('throws LogicException when setting input before usecase', function (): void {
// GIVEN
$executorMock = new class () implements UsecaseExecutor
{
public function execute(Usecase $usecase, Input $input, ?Presenter $presenter = null): object
{
return new \stdClass();
}
};
$inputMock = new class () implements Input
{
};
// WHEN & THEN
$builder = new UsecaseExecutionBuilder($executorMock);
expect(fn () => $builder->from($inputMock))
->toThrow(LogicException::class, 'Usecase must be set before input.');
});
it('throws LogicException when setting presenter before input or usecase', function (): void {
// GIVEN
$executorMock = new class () implements UsecaseExecutor
{
public function execute(Usecase $usecase, Input $input, ?Presenter $presenter = null): object
{
return new \stdClass();
}
};
$presenterMock = new class () implements Presenter
{
public function present(Output $output): object
{
return new \stdClass();
}
};
// WHEN & THEN
$builder = new UsecaseExecutionBuilder($executorMock);
expect(fn () => $builder->with($presenterMock))
->toThrow(LogicException::class, 'Usecase and input must be set before presenter.');
});
it('throws LogicException when running uncompleted builder', function (): void {
// GIVEN
$executorMock = new class () implements UsecaseExecutor
{
public function execute(Usecase $usecase, Input $input, ?Presenter $presenter = null): object
{
return new \stdClass();
}
};
// WHEN & THEN
$builder = new UsecaseExecutionBuilder($executorMock);
expect(fn () => $builder->run())
->toThrow(LogicException::class, 'Usecase and input are required.');
});
});