userRepo = new FakeUserRepository(); $this->hasher = new class implements PasswordHasher { public function hash(string $password): string { return 'hashed-' . $password; } public function verify(string $password, string $hash): bool { return $hash === 'hashed-' . $password; } }; $this->authenticateUser = new AuthenticateUser($this->userRepo, $this->hasher); } public function testAuthenticatesValidUser(): void { $email = new EmailAddress('user@example.com'); $this->userRepo->create(new \App\User\CreateUserDto($email, 'hashed-secret')); $request = new AuthenticateUserRequest('user@example.com', 'secret'); $user = $this->authenticateUser->execute($request); $this->assertInstanceOf(User::class, $user); $this->assertSame('user@example.com', $user->getEmail()->value()); } public function testThrowsWhenEmailMissing(): void { $this->expectException(BadRequestException::class); $this->expectExceptionMessage('email is required'); $request = new AuthenticateUserRequest(null, 'secret'); $this->authenticateUser->execute($request); } public function testThrowsWhenPasswordMissing(): void { $this->expectException(BadRequestException::class); $this->expectExceptionMessage('password is required'); $request = new AuthenticateUserRequest('user@example.com', null); $this->authenticateUser->execute($request); } public function testThrowsWhenUserNotFound(): void { $this->expectException(UnauthorizedException::class); $this->expectExceptionMessage('invalid credentials'); $request = new AuthenticateUserRequest('missing@example.com', 'secret'); $this->authenticateUser->execute($request); } public function testThrowsWhenPasswordIncorrect(): void { $email = new EmailAddress('user@example.com'); $this->userRepo->create(new \App\User\CreateUserDto($email, 'hashed-secret')); $this->expectException(UnauthorizedException::class); $this->expectExceptionMessage('invalid credentials'); $request = new AuthenticateUserRequest('user@example.com', 'wrong'); $this->authenticateUser->execute($request); } }