userRepository = $this->createMock(UserRepositoryInterface::class); $this->useCase = new AdminDeleteUser($this->userRepository); } public function testHandleThrowsNotFoundWhenTargetUserDoesNotExist(): void { $this->userRepository->expects($this->once()) ->method('findById') ->with(42) ->willReturn(null); $this->userRepository->expects($this->never())->method('delete'); $this->expectException(NotFoundException::class); $this->useCase->handle(new AdminDeleteUserCommand(1, 42)); } public function testHandleThrowsWhenTargetUserIsAdmin(): void { $admin = $this->makeUser(7, 'root', User::ROLE_ADMIN); $this->userRepository->expects($this->once()) ->method('findById') ->with(7) ->willReturn($admin); $this->userRepository->expects($this->never())->method('delete'); $this->expectException(ProtectedAdministratorDeletionException::class); $this->useCase->handle(new AdminDeleteUserCommand(1, 7)); } public function testHandleThrowsWhenActorTriesToDeleteOwnAccount(): void { $user = $this->makeUser(5, 'alice', User::ROLE_EDITOR); $this->userRepository->expects($this->once()) ->method('findById') ->with(5) ->willReturn($user); $this->userRepository->expects($this->never())->method('delete'); $this->expectException(CannotDeleteOwnAccountException::class); $this->useCase->handle(new AdminDeleteUserCommand(5, 5)); } public function testHandleDeletesUserAndReturnsTargetUserOnSuccess(): void { $user = $this->makeUser(9, 'charlie', User::ROLE_USER); $this->userRepository->expects($this->once()) ->method('findById') ->with(9) ->willReturn($user); $this->userRepository->expects($this->once()) ->method('delete') ->with(9); $result = $this->useCase->handle(new AdminDeleteUserCommand(1, 9)); $this->assertSame($user, $result); } private function makeUser(int $id, string $username, string $role): User { return new User($id, $username, sprintf('%s@example.com', $username), 'hashed-password', $role); } }