add unit tests

This commit is contained in:
natlinux
2026-05-09 18:10:05 +02:00
parent eb9b347bef
commit a813657667
10 changed files with 667 additions and 50 deletions
@@ -18,10 +18,17 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit.v3" Version="3.2.2" />
<PackageReference Include="NSubstitute" Version="5.3.0" />
</ItemGroup>
<ItemGroup>
<Using Include="Xunit"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Application\Application.csproj" />
<ProjectReference Include="..\..\src\Domain\Domain.csproj" />
<ProjectReference Include="..\..\src\Infrastructure\Infrastructure.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,285 @@
using Application.Common.Results;
using Application.DTOs;
using Application.Errors;
using Application.Interfaces;
using Application.Models;
using Application.Services;
using Application.Validators;
using Domain.Entities;
using Domain.Interface;
using Microsoft.AspNetCore.Identity;
using NSubstitute;
namespace Application.UnitTest.Services;
public class AuthenticationServiceTests
{
private readonly IUnitOfWork _unitOfWork = Substitute.For<IUnitOfWork>();
private readonly IUserRepository _userRepository = Substitute.For<IUserRepository>();
private readonly IJwtService _jwtService = Substitute.For<IJwtService>();
private readonly IEmailService _emailService = Substitute.For<IEmailService>();
private readonly AuthenticationService _sut;
public AuthenticationServiceTests()
{
_sut = new AuthenticationService(
_unitOfWork,
_userRepository,
new LoginRequestValidator(),
new RegisterRequestValidator(),
_jwtService,
_emailService);
}
[Fact]
public async Task RegisterAsync_ShouldReturnSuccess_WhenRequestIsValid()
{
var request = new RegisterRequest("newuser", "new@example.com", "ValidP@ss1!");
_userRepository.GetUserByEmailAsync(request.Email).Returns((User?)null);
_userRepository.GetUserByUsernameAsync(request.Username).Returns((User?)null);
var result = await _sut.RegisterAsync(request);
Assert.True(result.IsSuccess);
await _userRepository.Received(1).AddAsync(Arg.Any<User>());
await _unitOfWork.Received(1).CommitAsync();
}
[Fact]
public async Task RegisterAsync_ShouldReturnFailure_WhenValidationFails()
{
var request = new RegisterRequest("", "", "");
var result = await _sut.RegisterAsync(request);
Assert.True(result.IsFailure);
Assert.Equal(ErrorTypeConstant.ValidationError, result.Error.Code);
}
[Fact]
public async Task RegisterAsync_ShouldReturnFailure_WhenEmailAlreadyExists()
{
var request = new RegisterRequest("newuser", "existing@example.com", "ValidP@ss1!");
_userRepository.GetUserByEmailAsync(request.Email).Returns(new User
{
Username = "existing", Email = "existing@example.com", Password = "hash"
});
var result = await _sut.RegisterAsync(request);
Assert.True(result.IsFailure);
Assert.Equal(AuthError.EmailAlreadyExists, result.Error);
}
[Fact]
public async Task RegisterAsync_ShouldReturnFailure_WhenUsernameAlreadyExists()
{
var request = new RegisterRequest("existinguser", "new@example.com", "ValidP@ss1!");
_userRepository.GetUserByEmailAsync(request.Email).Returns((User?)null);
_userRepository.GetUserByUsernameAsync(request.Username).Returns(new User
{
Username = "existinguser", Email = "existing@example.com", Password = "hash"
});
var result = await _sut.RegisterAsync(request);
Assert.True(result.IsFailure);
Assert.Equal(AuthError.UsernameAlreadyExists, result.Error);
}
[Fact]
public async Task LoginAsync_ShouldReturnSuccess_WhenCredentialsAreValid()
{
var password = "ValidP@ss1!";
var user = new User
{
Id = 1,
Username = "testuser",
Email = "test@example.com",
Password = new PasswordHasher<User>().HashPassword(
new User { Username = "testuser", Email = "test@example.com", Password = password },
password)
};
var request = new LoginRequest(user.Email, password);
_userRepository.GetUserByEmailAsync(request.Email).Returns(user);
_jwtService.GenerateTokenAsync(user).Returns("access-token");
_jwtService.GenerateAndSaveRefreshTokenAsync(user).Returns("refresh-token");
var result = await _sut.LoginAsync(request);
Assert.True(result.IsSuccess);
_userRepository.Received(1).Update(user);
}
[Fact]
public async Task LoginAsync_ShouldReturnFailure_WhenValidationFails()
{
var request = new LoginRequest("", "");
var result = await _sut.LoginAsync(request);
Assert.True(result.IsFailure);
Assert.Equal(ErrorTypeConstant.ValidationError, result.Error.Code);
}
[Fact]
public async Task LoginAsync_ShouldReturnFailure_WhenUserNotFound()
{
var request = new LoginRequest("unknown@example.com", "password123");
_userRepository.GetUserByEmailAsync(request.Email).Returns((User?)null);
var result = await _sut.LoginAsync(request);
Assert.True(result.IsFailure);
Assert.Equal(AuthError.UserNotFound, result.Error);
}
[Fact]
public async Task RefreshTokensAsync_ShouldReturnSuccess_WhenRefreshTokenIsValid()
{
var request = new RefreshTokenRequest { UserId = 1, RefreshToken = "valid-refresh-token" };
var user = new User { Id = 1, Username = "testuser", Email = "test@example.com", Password = "hash" };
_jwtService.ValidateRefreshTokenAsync(request.UserId, request.RefreshToken).Returns(user);
_jwtService.GenerateTokenAsync(user).Returns("new-access-token");
_jwtService.GenerateAndSaveRefreshTokenAsync(user).Returns("new-refresh-token");
var result = await _sut.RefreshTokensAsync(request);
Assert.True(result.IsSuccess);
}
[Fact]
public async Task RefreshTokensAsync_ShouldReturnFailure_WhenUserNotFound()
{
var request = new RefreshTokenRequest { UserId = 99, RefreshToken = "invalid-token" };
_jwtService.ValidateRefreshTokenAsync(request.UserId, request.RefreshToken).Returns((User?)null);
var result = await _sut.RefreshTokensAsync(request);
Assert.True(result.IsFailure);
Assert.Equal(AuthError.UserNotFound, result.Error);
}
[Fact]
public async Task SendResetEmailAsync_ShouldReturnSuccess_WhenUserExists()
{
var email = "test@example.com";
var user = new User { Id = 1, Username = "testuser", Email = email, Password = "hash" };
_userRepository.GetUserByEmailAsync(email).Returns(user);
var result = await _sut.SendResetEmailAsync(email);
Assert.True(result.IsSuccess);
_emailService.Received(1).SendEmailAsync(Arg.Any<EmailRequest>());
_userRepository.Received(1).Update(user);
await _unitOfWork.Received(1).CommitAsync();
}
[Fact]
public async Task SendResetEmailAsync_ShouldReturnFailure_WhenUserNotFound()
{
var email = "unknown@example.com";
_userRepository.GetUserByEmailAsync(email).Returns((User?)null);
var result = await _sut.SendResetEmailAsync(email);
Assert.True(result.IsFailure);
Assert.Equal(AuthError.UserNotFound, result.Error);
}
[Fact]
public async Task ResetPasswordAsync_ShouldReturnSuccess_WhenTokenIsValid()
{
var dto = new ResetPasswordDto
{
Email = "test@example.com",
EmailToken = "valid-token",
NewPassword = "NewValidP@ss1"
};
var user = new User
{
Id = 1,
Username = "testuser",
Email = dto.Email,
Password = "old-hash",
ResetPasswordToken = "valid-token",
ResetPasswordTokenExpiryTime = DateTime.UtcNow.AddHours(1)
};
_userRepository.GetUserByEmailAsync(dto.Email).Returns(user);
var result = await _sut.ResetPasswordAsync(dto);
Assert.True(result.IsSuccess);
_userRepository.Received(1).Update(user);
await _unitOfWork.Received(1).CommitAsync();
}
[Fact]
public async Task ResetPasswordAsync_ShouldReturnFailure_WhenUserNotFound()
{
var dto = new ResetPasswordDto
{
Email = "unknown@example.com",
EmailToken = "token",
NewPassword = "NewValidP@ss1"
};
_userRepository.GetUserByEmailAsync(dto.Email).Returns((User?)null);
var result = await _sut.ResetPasswordAsync(dto);
Assert.True(result.IsFailure);
Assert.Equal(AuthError.UserNotFound, result.Error);
}
[Fact]
public async Task ResetPasswordAsync_ShouldReturnFailure_WhenTokenIsInvalid()
{
var dto = new ResetPasswordDto
{
Email = "test@example.com",
EmailToken = "wrong-token",
NewPassword = "NewValidP@ss1"
};
var user = new User
{
Id = 1,
Username = "testuser",
Email = dto.Email,
Password = "old-hash",
ResetPasswordToken = "valid-token",
ResetPasswordTokenExpiryTime = DateTime.UtcNow.AddHours(1)
};
_userRepository.GetUserByEmailAsync(dto.Email).Returns(user);
var result = await _sut.ResetPasswordAsync(dto);
Assert.True(result.IsFailure);
Assert.Equal(AuthError.InvalidResetLink, result.Error);
}
[Fact]
public async Task ResetPasswordAsync_ShouldReturnFailure_WhenTokenIsExpired()
{
var dto = new ResetPasswordDto
{
Email = "test@example.com",
EmailToken = "valid-token",
NewPassword = "NewValidP@ss1"
};
var user = new User
{
Id = 1,
Username = "testuser",
Email = dto.Email,
Password = "old-hash",
ResetPasswordToken = "valid-token",
ResetPasswordTokenExpiryTime = DateTime.UtcNow.AddHours(-1)
};
_userRepository.GetUserByEmailAsync(dto.Email).Returns(user);
var result = await _sut.ResetPasswordAsync(dto);
Assert.True(result.IsFailure);
Assert.Equal(AuthError.InvalidResetLink, result.Error);
}
}
@@ -0,0 +1,222 @@
using Application.Common.Results;
using Application.DTOs;
using Application.Errors;
using Application.Models;
using Application.Services;
using Application.Validators;
using Domain.Entities;
using Domain.Interface;
using NSubstitute;
namespace Application.UnitTest.Services;
public class UserServiceTests
{
private readonly IUnitOfWork _unitOfWork = Substitute.For<IUnitOfWork>();
private readonly IUserRepository _userRepository = Substitute.For<IUserRepository>();
private readonly IUserRoleRepository _userRoleRepository = Substitute.For<IUserRoleRepository>();
private readonly UserService _sut;
public UserServiceTests()
{
_sut = new UserService(
_unitOfWork,
new UserUpdateRequestValidator(),
_userRepository,
_userRoleRepository);
}
[Fact]
public async Task GetAsync_ShouldReturnPagedResults()
{
var users = new List<User>
{
new() { Id = 1, Username = "user1", Email = "user1@test.com", Password = "hash",
UserRoles = [new UserRole { Role = new Role { Id = 1, Name = "Admin" } }] },
new() { Id = 2, Username = "user2", Email = "user2@test.com", Password = "hash",
UserRoles = [new UserRole { Role = new Role { Id = 2, Name = "User" } }] }
};
_userRepository.GetAllAsync().Returns(users);
var result = await _sut.GetAsync(1, 10);
Assert.True(result.IsSuccess);
Assert.Equal(2, result.Value.Items.Count);
Assert.Equal(2, result.Value.TotalCount);
}
[Fact]
public async Task UpdateAsync_ShouldReturnSuccess_WhenRequestIsValid()
{
var request = new UserUpdateRequest(1, "updateduser", "updated@test.com");
var user = new User { Id = 1, Username = "olduser", Email = "old@test.com", Password = "hash" };
_userRepository.GetByIdAsync(request.Id).Returns(user);
var result = await _sut.UpdateAsync(request);
Assert.True(result.IsSuccess);
Assert.Equal(request.Username, user.Username);
Assert.Equal(request.Email, user.Email);
_userRepository.Received(1).Update(user);
await _unitOfWork.Received(1).CommitAsync();
}
[Fact]
public async Task UpdateAsync_ShouldReturnFailure_WhenValidationFails()
{
var request = new UserUpdateRequest(0, "", "");
var result = await _sut.UpdateAsync(request);
Assert.True(result.IsFailure);
Assert.Equal(ErrorTypeConstant.ValidationError, result.Error.Code);
}
[Fact]
public async Task UpdateAsync_ShouldReturnFailure_WhenUserNotFound()
{
var request = new UserUpdateRequest(99, "user", "user@test.com");
_userRepository.GetByIdAsync(request.Id).Returns((User?)null);
var result = await _sut.UpdateAsync(request);
Assert.True(result.IsFailure);
Assert.Equal(UserError.UserNotFound, result.Error);
}
[Fact]
public async Task DeleteAsync_ShouldReturnSuccess_WhenUserExists()
{
var user = new User { Id = 2, Username = "user2", Email = "user2@test.com", Password = "hash" };
_userRepository.GetByIdAsync(2).Returns(user);
var result = await _sut.DeleteAsync(2, 1);
Assert.True(result.IsSuccess);
_userRepository.Received(1).Delete(user);
await _unitOfWork.Received(1).CommitAsync();
}
[Fact]
public async Task DeleteAsync_ShouldReturnFailure_WhenDeletingYourself()
{
var result = await _sut.DeleteAsync(1, 1);
Assert.True(result.IsFailure);
Assert.Equal(UserError.CannotDeleteYourself, result.Error);
}
[Fact]
public async Task DeleteAsync_ShouldReturnFailure_WhenUserNotFound()
{
_userRepository.GetByIdAsync(99).Returns((User?)null);
var result = await _sut.DeleteAsync(99, 1);
Assert.True(result.IsFailure);
Assert.Equal(UserError.UserNotFound, result.Error);
}
[Fact]
public async Task GetUserByIdAsync_ShouldReturnUser_WhenUserExists()
{
var user = new User
{
Id = 1, Username = "testuser", Email = "test@test.com", Password = "hash",
UserRoles = [new UserRole { Role = new Role { Id = 1, Name = "Admin" } }]
};
_userRepository.GetByIdAsync(1).Returns(user);
var result = await _sut.GetUserByIdAsync(1);
Assert.True(result.IsSuccess);
Assert.Equal(user.Id, result.Value.Id);
Assert.Equal(user.Username, result.Value.Username);
Assert.Equal(user.Email, result.Value.Email);
}
[Fact]
public async Task GetUserByIdAsync_ShouldReturnFailure_WhenUserNotFound()
{
_userRepository.GetByIdAsync(99).Returns((User?)null);
var result = await _sut.GetUserByIdAsync(99);
Assert.True(result.IsFailure);
Assert.Equal(UserError.UserNotFound, result.Error);
}
[Fact]
public async Task AssignRoleAsync_ShouldReturnSuccess_WhenUserDoesNotHaveRole()
{
var request = new AssingRoleRequest(1, 2);
_userRoleRepository.HasRoleAsync(request.UserId, request.RoleId).Returns(false);
_userRoleRepository.AddRoleAsync(request.UserId, request.RoleId).Returns(true);
var result = await _sut.AssignRoleAsync(request);
Assert.True(result.IsSuccess);
}
[Fact]
public async Task AssignRoleAsync_ShouldReturnFailure_WhenUserAlreadyHasRole()
{
var request = new AssingRoleRequest(1, 2);
_userRoleRepository.HasRoleAsync(request.UserId, request.RoleId).Returns(true);
var result = await _sut.AssignRoleAsync(request);
Assert.True(result.IsFailure);
Assert.Equal(UserError.UserAlreadyHasRole, result.Error);
}
[Fact]
public async Task AssignRoleAsync_ShouldReturnFailure_WhenAddRoleFails()
{
var request = new AssingRoleRequest(1, 2);
_userRoleRepository.HasRoleAsync(request.UserId, request.RoleId).Returns(false);
_userRoleRepository.AddRoleAsync(request.UserId, request.RoleId).Returns(false);
var result = await _sut.AssignRoleAsync(request);
Assert.True(result.IsFailure);
Assert.Equal(UserError.FailedToAssignRole, result.Error);
}
[Fact]
public async Task RevokeRoleAsync_ShouldReturnSuccess_WhenUserHasRole()
{
var request = new AssingRoleRequest(1, 2);
_userRoleRepository.HasRoleAsync(request.UserId, request.RoleId).Returns(true);
_userRoleRepository.RemoveRoleAsync(request.UserId, request.RoleId).Returns(true);
var result = await _sut.RevokeRoleAsync(request);
Assert.True(result.IsSuccess);
}
[Fact]
public async Task RevokeRoleAsync_ShouldReturnFailure_WhenUserHasNoRole()
{
var request = new AssingRoleRequest(1, 2);
_userRoleRepository.HasRoleAsync(request.UserId, request.RoleId).Returns(false);
var result = await _sut.RevokeRoleAsync(request);
Assert.True(result.IsFailure);
Assert.Equal(UserError.UserHasNoRole, result.Error);
}
[Fact]
public async Task RevokeRoleAsync_ShouldReturnFailure_WhenRemoveRoleFails()
{
var request = new AssingRoleRequest(1, 2);
_userRoleRepository.HasRoleAsync(request.UserId, request.RoleId).Returns(true);
_userRoleRepository.RemoveRoleAsync(request.UserId, request.RoleId).Returns(false);
var result = await _sut.RevokeRoleAsync(request);
Assert.True(result.IsFailure);
Assert.Equal(UserError.FailedToRevokeRole, result.Error);
}
}
-9
View File
@@ -1,9 +0,0 @@
namespace Application.UnitTest;
public class UnitTest1
{
[Fact]
public void Test1()
{
}
}
@@ -0,0 +1,33 @@
using Application.Models;
using Application.Validators;
namespace Application.UnitTest.Validators;
public class LoginRequestValidatorTests
{
private readonly LoginRequestValidator _sut = new();
[Fact]
public void Validate_ShouldPass_WhenAllFieldsAreValid()
{
var request = new LoginRequest("test@example.com", "password123");
var result = _sut.Validate(request);
Assert.True(result.IsValid);
}
[Theory]
[InlineData("", "password123", "Email")]
[InlineData("not-an-email", "password123", "Email")]
[InlineData("test@example.com", "", "Password")]
public void Validate_ShouldFail_WhenFieldIsInvalid(string email, string password, string expectedProperty)
{
var request = new LoginRequest(email, password);
var result = _sut.Validate(request);
Assert.False(result.IsValid);
Assert.Contains(result.Errors, e => e.PropertyName == expectedProperty);
}
}
@@ -0,0 +1,41 @@
using Application.Models;
using Application.Validators;
namespace Application.UnitTest.Validators;
public class RegisterRequestValidatorTests
{
private readonly RegisterRequestValidator _sut = new();
[Fact]
public void Validate_ShouldPass_WhenAllFieldsAreValid()
{
var request = new RegisterRequest("ValidUser", "test@example.com", "ValidP@ss1");
var result = _sut.Validate(request);
Assert.True(result.IsValid);
}
[Theory]
[InlineData("ValidUser", "", "ValidP@ss1", "Email")]
[InlineData("ValidUser", "invalid-email", "ValidP@ss1", "Email")]
[InlineData("ValidUser", "test@example.com", "", "Password")]
[InlineData("ValidUser", "test@example.com", "short1A@", "Password")]
[InlineData("ValidUser", "test@example.com", "nouppercase1@", "Password")]
[InlineData("ValidUser", "test@example.com", "NOLOWERCASE1@", "Password")]
[InlineData("ValidUser", "test@example.com", "NoDigit@aa", "Password")]
[InlineData("ValidUser", "test@example.com", "NoSpecialChar1", "Password")]
[InlineData("", "test@example.com", "ValidP@ss1", "Username")]
[InlineData("ab", "test@example.com", "ValidP@ss1", "Username")]
[InlineData("user@name", "test@example.com", "ValidP@ss1", "Username")]
public void Validate_ShouldFail_WhenFieldIsInvalid(string username, string email, string password, string expectedProperty)
{
var request = new RegisterRequest(username, email, password);
var result = _sut.Validate(request);
Assert.False(result.IsValid);
Assert.Contains(result.Errors, e => e.PropertyName == expectedProperty);
}
}
@@ -0,0 +1,34 @@
using Application.Models;
using Application.Validators;
namespace Application.UnitTest.Validators;
public class UserUpdateRequestValidatorTests
{
private readonly UserUpdateRequestValidator _sut = new();
[Fact]
public void Validate_ShouldPass_WhenAllFieldsAreValid()
{
var request = new UserUpdateRequest(1, "ValidUser", "test@example.com");
var result = _sut.Validate(request);
Assert.True(result.IsValid);
}
[Theory]
[InlineData(0, "ValidUser", "test@example.com", "Id")]
[InlineData(1, "", "test@example.com", "Username")]
[InlineData(1, "ValidUser", "", "Email")]
[InlineData(1, "ValidUser", "invalid-email", "Email")]
public void Validate_ShouldFail_WhenFieldIsInvalid(int id, string username, string email, string expectedProperty)
{
var request = new UserUpdateRequest(id, username, email);
var result = _sut.Validate(request);
Assert.False(result.IsValid);
Assert.Contains(result.Errors, e => e.PropertyName == expectedProperty);
}
}