academia/tests/Application.Tests/Auth/LoginCommandTests.cs

172 lines
5.9 KiB
C#

namespace Application.Tests.Auth;
using Application.Auth;
using Application.Auth.Commands;
using Domain.Entities;
using Domain.Ports.Repositories;
using FluentAssertions;
using NSubstitute;
using Xunit;
public class LoginCommandTests
{
private readonly IUserRepository _userRepository;
private readonly IPasswordService _passwordService;
private readonly IJwtService _jwtService;
private readonly LoginCommandHandler _handler;
public LoginCommandTests()
{
_userRepository = Substitute.For<IUserRepository>();
_passwordService = Substitute.For<IPasswordService>();
_jwtService = Substitute.For<IJwtService>();
_handler = new LoginCommandHandler(_userRepository, _passwordService, _jwtService);
}
[Fact]
public async Task Handle_WithValidCredentials_ShouldReturnSuccessWithToken()
{
// Arrange
var user = CreateUser("testuser", "hashed_password");
_userRepository.GetByUsernameAsync("testuser", Arg.Any<CancellationToken>())
.Returns(user);
_passwordService.VerifyPassword("password123", "hashed_password")
.Returns(true);
_jwtService.GenerateToken(user)
.Returns("valid.jwt.token");
var command = new LoginCommand("testuser", "password123");
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.Should().NotBeNull();
result.Success.Should().BeTrue();
result.Token.Should().Be("valid.jwt.token");
result.User.Should().NotBeNull();
result.User!.Username.Should().Be("testuser");
result.Error.Should().BeNull();
}
[Fact]
public async Task Handle_WithInvalidUsername_ShouldReturnError()
{
// Arrange
_userRepository.GetByUsernameAsync("nonexistent", Arg.Any<CancellationToken>())
.Returns((User?)null);
var command = new LoginCommand("nonexistent", "password123");
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.Success.Should().BeFalse();
result.Token.Should().BeNull();
result.Error.Should().Contain("incorrectos");
}
[Fact]
public async Task Handle_WithInvalidPassword_ShouldReturnError()
{
// Arrange
var user = CreateUser("testuser", "hashed_password");
_userRepository.GetByUsernameAsync("testuser", Arg.Any<CancellationToken>())
.Returns(user);
_passwordService.VerifyPassword("wrongpassword", "hashed_password")
.Returns(false);
var command = new LoginCommand("testuser", "wrongpassword");
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.Success.Should().BeFalse();
result.Token.Should().BeNull();
result.Error.Should().Contain("incorrectos");
}
[Fact]
public async Task Handle_ShouldNormalizUsernameToLowercase()
{
// Arrange
var user = CreateUser("testuser", "hashed_password");
_userRepository.GetByUsernameAsync("testuser", Arg.Any<CancellationToken>())
.Returns(user);
_passwordService.VerifyPassword("password123", "hashed_password")
.Returns(true);
_jwtService.GenerateToken(user)
.Returns("valid.jwt.token");
var command = new LoginCommand("TESTUSER", "password123");
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.Success.Should().BeTrue();
await _userRepository.Received(1).GetByUsernameAsync("testuser", Arg.Any<CancellationToken>());
}
[Fact]
public async Task Handle_ShouldUpdateLastLoginOnSuccess()
{
// Arrange
var user = CreateUser("testuser", "hashed_password");
_userRepository.GetByUsernameAsync("testuser", Arg.Any<CancellationToken>())
.Returns(user);
_passwordService.VerifyPassword("password123", "hashed_password")
.Returns(true);
_jwtService.GenerateToken(user)
.Returns("valid.jwt.token");
var command = new LoginCommand("testuser", "password123");
// Act
await _handler.Handle(command, CancellationToken.None);
// Assert
await _userRepository.Received(1).UpdateAsync(user, Arg.Any<CancellationToken>());
}
[Fact]
public async Task Handle_WithStudentUser_ShouldIncludeStudentInfo()
{
// Arrange
var user = CreateUserWithStudent("studentuser", "hashed_password", 1, "John Doe");
_userRepository.GetByUsernameAsync("studentuser", Arg.Any<CancellationToken>())
.Returns(user);
_passwordService.VerifyPassword("password123", "hashed_password")
.Returns(true);
_jwtService.GenerateToken(user)
.Returns("valid.jwt.token");
var command = new LoginCommand("studentuser", "password123");
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.Success.Should().BeTrue();
result.User!.StudentId.Should().Be(1);
result.User.StudentName.Should().Be("John Doe");
result.User.Role.Should().Be(UserRoles.Student);
}
private static User CreateUser(string username, string passwordHash)
{
return User.Create(username, passwordHash, "recovery_hash", UserRoles.Student);
}
private static User CreateUserWithStudent(string username, string passwordHash, int studentId, string studentName)
{
var user = User.Create(username, passwordHash, "recovery_hash", UserRoles.Student, studentId);
// Set up the Student navigation property
var student = new Student(studentName, Domain.ValueObjects.Email.Create($"{username}@test.com"));
typeof(User).GetProperty("Student")?.SetValue(user, student);
return user;
}
}