- 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.
185 lines
5.3 KiB
PHP
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.');
|
|
});
|
|
});
|