Add initial implementation of API, database, and user management components.
This commit is contained in:
104
MikrocopTests/AuthServiceTests.cs
Normal file
104
MikrocopTests/AuthServiceTests.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
using MikrocopApi.Dtos;
|
||||
using MikrocopApi.Exceptions;
|
||||
using MikrocopApi.Services;
|
||||
using MikrocopDb.Entities;
|
||||
using MikrocopDb.Repositories;
|
||||
using Moq;
|
||||
|
||||
namespace MikrocopTests;
|
||||
|
||||
[TestFixture]
|
||||
public sealed class AuthServiceTests
|
||||
{
|
||||
[Test]
|
||||
public async Task LoginAsync_ReturnsToken_WhenCredentialsAreValid()
|
||||
{
|
||||
var user = CreateUser();
|
||||
var repositoryMock = new Mock<IUserRepository>(MockBehavior.Strict);
|
||||
var hashingServiceMock = new Mock<IPasswordHashingService>(MockBehavior.Strict);
|
||||
var jwtTokenServiceMock = new Mock<IJwtTokenService>(MockBehavior.Strict);
|
||||
var request = new LoginRequestDto { UserName = user.UserName, Password = "ValidPassword!123" };
|
||||
var expectedExpiry = DateTime.UtcNow.AddHours(1);
|
||||
|
||||
repositoryMock
|
||||
.Setup(x => x.GetByUserNameAsync(request.UserName, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(user);
|
||||
hashingServiceMock
|
||||
.Setup(x => x.VerifyPassword(request.Password, user.PasswordHash, user.PasswordSalt))
|
||||
.Returns(true);
|
||||
jwtTokenServiceMock
|
||||
.Setup(x => x.Generate(user))
|
||||
.Returns(("token-value", expectedExpiry));
|
||||
|
||||
var sut = new AuthService(repositoryMock.Object, hashingServiceMock.Object, jwtTokenServiceMock.Object);
|
||||
|
||||
var result = await sut.LoginAsync(request);
|
||||
|
||||
Assert.That(result.AccessToken, Is.EqualTo("token-value"));
|
||||
Assert.That(result.ExpiresAtUtc, Is.EqualTo(expectedExpiry));
|
||||
Assert.That(result.TokenType, Is.EqualTo("Bearer"));
|
||||
repositoryMock.VerifyAll();
|
||||
hashingServiceMock.VerifyAll();
|
||||
jwtTokenServiceMock.VerifyAll();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LoginAsync_ThrowsUnauthorized_WhenUserDoesNotExist()
|
||||
{
|
||||
var repositoryMock = new Mock<IUserRepository>(MockBehavior.Strict);
|
||||
var hashingServiceMock = new Mock<IPasswordHashingService>(MockBehavior.Strict);
|
||||
var jwtTokenServiceMock = new Mock<IJwtTokenService>(MockBehavior.Strict);
|
||||
var request = new LoginRequestDto { UserName = "missing", Password = "ValidPassword!123" };
|
||||
|
||||
repositoryMock
|
||||
.Setup(x => x.GetByUserNameAsync(request.UserName, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((UserEntity?)null);
|
||||
|
||||
var sut = new AuthService(repositoryMock.Object, hashingServiceMock.Object, jwtTokenServiceMock.Object);
|
||||
|
||||
Assert.ThrowsAsync<UnauthorizedException>(() => sut.LoginAsync(request));
|
||||
repositoryMock.VerifyAll();
|
||||
hashingServiceMock.VerifyNoOtherCalls();
|
||||
jwtTokenServiceMock.VerifyNoOtherCalls();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LoginAsync_ThrowsUnauthorized_WhenPasswordIsInvalid()
|
||||
{
|
||||
var user = CreateUser();
|
||||
var repositoryMock = new Mock<IUserRepository>(MockBehavior.Strict);
|
||||
var hashingServiceMock = new Mock<IPasswordHashingService>(MockBehavior.Strict);
|
||||
var jwtTokenServiceMock = new Mock<IJwtTokenService>(MockBehavior.Strict);
|
||||
var request = new LoginRequestDto { UserName = user.UserName, Password = "WrongPassword!123" };
|
||||
|
||||
repositoryMock
|
||||
.Setup(x => x.GetByUserNameAsync(request.UserName, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(user);
|
||||
hashingServiceMock
|
||||
.Setup(x => x.VerifyPassword(request.Password, user.PasswordHash, user.PasswordSalt))
|
||||
.Returns(false);
|
||||
|
||||
var sut = new AuthService(repositoryMock.Object, hashingServiceMock.Object, jwtTokenServiceMock.Object);
|
||||
|
||||
Assert.ThrowsAsync<UnauthorizedException>(() => sut.LoginAsync(request));
|
||||
repositoryMock.VerifyAll();
|
||||
hashingServiceMock.VerifyAll();
|
||||
jwtTokenServiceMock.VerifyNoOtherCalls();
|
||||
}
|
||||
|
||||
private static UserEntity CreateUser()
|
||||
{
|
||||
return new UserEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
UserName = "test-user",
|
||||
FullName = "Test User",
|
||||
Email = "test@example.com",
|
||||
MobileNumber = "+38640111222",
|
||||
Language = "en",
|
||||
Culture = "en-US",
|
||||
PasswordHash = "hash",
|
||||
PasswordSalt = "salt"
|
||||
};
|
||||
}
|
||||
}
|
||||
29
MikrocopTests/MikrocopTests.csproj
Normal file
29
MikrocopTests/MikrocopTests.csproj
Normal file
@@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0"/>
|
||||
<PackageReference Include="Moq" Version="4.20.72"/>
|
||||
<PackageReference Include="NUnit" Version="4.3.2"/>
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.7.0"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="NUnit.Framework"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MikrocopApi\MikrocopApi.csproj" />
|
||||
<ProjectReference Include="..\MikrocopDb\MikrocopDb.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
401
MikrocopTests/UserServiceTests.cs
Normal file
401
MikrocopTests/UserServiceTests.cs
Normal file
@@ -0,0 +1,401 @@
|
||||
using MikrocopApi.Dtos;
|
||||
using MikrocopApi.Exceptions;
|
||||
using MikrocopApi.Services;
|
||||
using MikrocopDb.Entities;
|
||||
using MikrocopDb.Repositories;
|
||||
using Moq;
|
||||
|
||||
namespace MikrocopTests;
|
||||
|
||||
[TestFixture]
|
||||
public sealed class UserServiceTests
|
||||
{
|
||||
[Test]
|
||||
public async Task CreateAsync_ReturnsCreatedUser_WhenRequestIsValid()
|
||||
{
|
||||
var repositoryMock = new Mock<IUserRepository>(MockBehavior.Strict);
|
||||
var hashingServiceMock = new Mock<IPasswordHashingService>(MockBehavior.Strict);
|
||||
var request = CreateRequest();
|
||||
|
||||
repositoryMock.Setup(x => x.GetByUserNameAsync(request.UserName, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((UserEntity?)null);
|
||||
repositoryMock.Setup(x => x.GetByEmailAsync(request.Email, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((UserEntity?)null);
|
||||
hashingServiceMock.Setup(x => x.HashPassword(request.Password))
|
||||
.Returns(("hash-value", "salt-value"));
|
||||
repositoryMock.Setup(x => x.AddAsync(It.IsAny<UserEntity>(), It.IsAny<CancellationToken>()))
|
||||
.Returns(Task.CompletedTask);
|
||||
|
||||
var sut = new UserService(repositoryMock.Object, hashingServiceMock.Object);
|
||||
|
||||
var result = await sut.CreateAsync(request);
|
||||
|
||||
Assert.That(result.UserName, Is.EqualTo("new-user"));
|
||||
Assert.That(result.Email, Is.EqualTo("new.user@example.com"));
|
||||
repositoryMock.Verify(x => x.AddAsync(It.Is<UserEntity>(u =>
|
||||
u.UserName == "new-user" &&
|
||||
u.FullName == "New User" &&
|
||||
u.Email == "new.user@example.com" &&
|
||||
u.PasswordHash == "hash-value" &&
|
||||
u.PasswordSalt == "salt-value"),
|
||||
It.IsAny<CancellationToken>()), Times.Once);
|
||||
repositoryMock.VerifyAll();
|
||||
hashingServiceMock.VerifyAll();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateAsync_ThrowsConflict_WhenUserNameExists()
|
||||
{
|
||||
var repositoryMock = new Mock<IUserRepository>(MockBehavior.Strict);
|
||||
var hashingServiceMock = new Mock<IPasswordHashingService>(MockBehavior.Strict);
|
||||
var request = CreateRequest();
|
||||
|
||||
repositoryMock.Setup(x => x.GetByUserNameAsync(request.UserName, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(CreateEntity());
|
||||
|
||||
var sut = new UserService(repositoryMock.Object, hashingServiceMock.Object);
|
||||
|
||||
Assert.ThrowsAsync<ConflictException>(() => sut.CreateAsync(request));
|
||||
repositoryMock.VerifyAll();
|
||||
hashingServiceMock.VerifyNoOtherCalls();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateAsync_ThrowsConflict_WhenEmailExists()
|
||||
{
|
||||
var repositoryMock = new Mock<IUserRepository>(MockBehavior.Strict);
|
||||
var hashingServiceMock = new Mock<IPasswordHashingService>(MockBehavior.Strict);
|
||||
var request = CreateRequest();
|
||||
|
||||
repositoryMock.Setup(x => x.GetByUserNameAsync(request.UserName, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((UserEntity?)null);
|
||||
repositoryMock.Setup(x => x.GetByEmailAsync(request.Email, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(CreateEntity());
|
||||
|
||||
var sut = new UserService(repositoryMock.Object, hashingServiceMock.Object);
|
||||
|
||||
Assert.ThrowsAsync<ConflictException>(() => sut.CreateAsync(request));
|
||||
repositoryMock.VerifyAll();
|
||||
hashingServiceMock.VerifyNoOtherCalls();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateAsync_ThrowsBadRequest_WhenPasswordIsNotComplexEnough()
|
||||
{
|
||||
var repositoryMock = new Mock<IUserRepository>(MockBehavior.Strict);
|
||||
var hashingServiceMock = new Mock<IPasswordHashingService>(MockBehavior.Strict);
|
||||
var request = CreateRequest();
|
||||
request.Password = "weak";
|
||||
|
||||
repositoryMock.Setup(x => x.GetByUserNameAsync(request.UserName, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((UserEntity?)null);
|
||||
repositoryMock.Setup(x => x.GetByEmailAsync(request.Email, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((UserEntity?)null);
|
||||
|
||||
var sut = new UserService(repositoryMock.Object, hashingServiceMock.Object);
|
||||
|
||||
Assert.ThrowsAsync<BadRequestException>(() => sut.CreateAsync(request));
|
||||
repositoryMock.VerifyAll();
|
||||
hashingServiceMock.VerifyNoOtherCalls();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task UpdateAsync_UpdatesUserWithoutPassword_WhenPasswordIsNotProvided()
|
||||
{
|
||||
var repositoryMock = new Mock<IUserRepository>(MockBehavior.Strict);
|
||||
var hashingServiceMock = new Mock<IPasswordHashingService>(MockBehavior.Strict);
|
||||
var id = Guid.NewGuid();
|
||||
var existing = CreateEntity(id);
|
||||
var request = CreateUpdateRequest(password: null);
|
||||
|
||||
repositoryMock.Setup(x => x.GetByIdAsync(id, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(existing);
|
||||
repositoryMock.Setup(x => x.GetByUserNameAsync(request.UserName, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((UserEntity?)null);
|
||||
repositoryMock.Setup(x => x.GetByEmailAsync(request.Email, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((UserEntity?)null);
|
||||
repositoryMock.Setup(x => x.UpdateAsync(existing, It.IsAny<CancellationToken>()))
|
||||
.Returns(Task.CompletedTask);
|
||||
|
||||
var sut = new UserService(repositoryMock.Object, hashingServiceMock.Object);
|
||||
|
||||
await sut.UpdateAsync(id, request);
|
||||
|
||||
Assert.That(existing.UserName, Is.EqualTo(request.UserName));
|
||||
Assert.That(existing.PasswordHash, Is.EqualTo("hash"));
|
||||
repositoryMock.VerifyAll();
|
||||
hashingServiceMock.VerifyNoOtherCalls();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task UpdateAsync_HashesPassword_WhenPasswordIsProvided()
|
||||
{
|
||||
var repositoryMock = new Mock<IUserRepository>(MockBehavior.Strict);
|
||||
var hashingServiceMock = new Mock<IPasswordHashingService>(MockBehavior.Strict);
|
||||
var id = Guid.NewGuid();
|
||||
var existing = CreateEntity(id);
|
||||
var request = CreateUpdateRequest(password: "UpdatedPassword!123");
|
||||
|
||||
repositoryMock.Setup(x => x.GetByIdAsync(id, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(existing);
|
||||
repositoryMock.Setup(x => x.GetByUserNameAsync(request.UserName, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((UserEntity?)null);
|
||||
repositoryMock.Setup(x => x.GetByEmailAsync(request.Email, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((UserEntity?)null);
|
||||
hashingServiceMock.Setup(x => x.HashPassword(request.Password!))
|
||||
.Returns(("new-hash", "new-salt"));
|
||||
repositoryMock.Setup(x => x.UpdateAsync(existing, It.IsAny<CancellationToken>()))
|
||||
.Returns(Task.CompletedTask);
|
||||
|
||||
var sut = new UserService(repositoryMock.Object, hashingServiceMock.Object);
|
||||
|
||||
await sut.UpdateAsync(id, request);
|
||||
|
||||
Assert.That(existing.PasswordHash, Is.EqualTo("new-hash"));
|
||||
Assert.That(existing.PasswordSalt, Is.EqualTo("new-salt"));
|
||||
repositoryMock.VerifyAll();
|
||||
hashingServiceMock.VerifyAll();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateAsync_ThrowsNotFound_WhenUserDoesNotExist()
|
||||
{
|
||||
var repositoryMock = new Mock<IUserRepository>(MockBehavior.Strict);
|
||||
var hashingServiceMock = new Mock<IPasswordHashingService>(MockBehavior.Strict);
|
||||
var id = Guid.NewGuid();
|
||||
var request = CreateUpdateRequest(password: null);
|
||||
|
||||
repositoryMock.Setup(x => x.GetByIdAsync(id, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((UserEntity?)null);
|
||||
|
||||
var sut = new UserService(repositoryMock.Object, hashingServiceMock.Object);
|
||||
|
||||
Assert.ThrowsAsync<NotFoundException>(() => sut.UpdateAsync(id, request));
|
||||
repositoryMock.VerifyAll();
|
||||
hashingServiceMock.VerifyNoOtherCalls();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateAsync_ThrowsConflict_WhenUserNameBelongsToAnotherUser()
|
||||
{
|
||||
var repositoryMock = new Mock<IUserRepository>(MockBehavior.Strict);
|
||||
var hashingServiceMock = new Mock<IPasswordHashingService>(MockBehavior.Strict);
|
||||
var id = Guid.NewGuid();
|
||||
var request = CreateUpdateRequest(password: null);
|
||||
|
||||
repositoryMock.Setup(x => x.GetByIdAsync(id, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(CreateEntity(id));
|
||||
repositoryMock.Setup(x => x.GetByUserNameAsync(request.UserName, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(CreateEntity(Guid.NewGuid()));
|
||||
|
||||
var sut = new UserService(repositoryMock.Object, hashingServiceMock.Object);
|
||||
|
||||
Assert.ThrowsAsync<ConflictException>(() => sut.UpdateAsync(id, request));
|
||||
repositoryMock.VerifyAll();
|
||||
hashingServiceMock.VerifyNoOtherCalls();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateAsync_ThrowsConflict_WhenEmailBelongsToAnotherUser()
|
||||
{
|
||||
var repositoryMock = new Mock<IUserRepository>(MockBehavior.Strict);
|
||||
var hashingServiceMock = new Mock<IPasswordHashingService>(MockBehavior.Strict);
|
||||
var id = Guid.NewGuid();
|
||||
var request = CreateUpdateRequest(password: null);
|
||||
|
||||
repositoryMock.Setup(x => x.GetByIdAsync(id, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(CreateEntity(id));
|
||||
repositoryMock.Setup(x => x.GetByUserNameAsync(request.UserName, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((UserEntity?)null);
|
||||
repositoryMock.Setup(x => x.GetByEmailAsync(request.Email, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(CreateEntity(Guid.NewGuid()));
|
||||
|
||||
var sut = new UserService(repositoryMock.Object, hashingServiceMock.Object);
|
||||
|
||||
Assert.ThrowsAsync<ConflictException>(() => sut.UpdateAsync(id, request));
|
||||
repositoryMock.VerifyAll();
|
||||
hashingServiceMock.VerifyNoOtherCalls();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateAsync_ThrowsBadRequest_WhenProvidedPasswordIsWeak()
|
||||
{
|
||||
var repositoryMock = new Mock<IUserRepository>(MockBehavior.Strict);
|
||||
var hashingServiceMock = new Mock<IPasswordHashingService>(MockBehavior.Strict);
|
||||
var id = Guid.NewGuid();
|
||||
var request = CreateUpdateRequest(password: "weak");
|
||||
|
||||
repositoryMock.Setup(x => x.GetByIdAsync(id, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(CreateEntity(id));
|
||||
repositoryMock.Setup(x => x.GetByUserNameAsync(request.UserName, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((UserEntity?)null);
|
||||
repositoryMock.Setup(x => x.GetByEmailAsync(request.Email, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((UserEntity?)null);
|
||||
|
||||
var sut = new UserService(repositoryMock.Object, hashingServiceMock.Object);
|
||||
|
||||
Assert.ThrowsAsync<BadRequestException>(() => sut.UpdateAsync(id, request));
|
||||
repositoryMock.VerifyAll();
|
||||
hashingServiceMock.VerifyNoOtherCalls();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetByIdAsync_ReturnsUser_WhenUserExists()
|
||||
{
|
||||
var repositoryMock = new Mock<IUserRepository>(MockBehavior.Strict);
|
||||
var hashingServiceMock = new Mock<IPasswordHashingService>(MockBehavior.Strict);
|
||||
var id = Guid.NewGuid();
|
||||
var user = CreateEntity(id);
|
||||
|
||||
repositoryMock.Setup(x => x.GetByIdAsync(id, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(user);
|
||||
|
||||
var sut = new UserService(repositoryMock.Object, hashingServiceMock.Object);
|
||||
|
||||
var result = await sut.GetByIdAsync(id);
|
||||
|
||||
Assert.That(result.Id, Is.EqualTo(id));
|
||||
Assert.That(result.UserName, Is.EqualTo(user.UserName));
|
||||
repositoryMock.VerifyAll();
|
||||
hashingServiceMock.VerifyNoOtherCalls();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetByIdAsync_ThrowsNotFound_WhenUserDoesNotExist()
|
||||
{
|
||||
var repositoryMock = new Mock<IUserRepository>(MockBehavior.Strict);
|
||||
var hashingServiceMock = new Mock<IPasswordHashingService>(MockBehavior.Strict);
|
||||
var id = Guid.NewGuid();
|
||||
|
||||
repositoryMock.Setup(x => x.GetByIdAsync(id, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((UserEntity?)null);
|
||||
|
||||
var sut = new UserService(repositoryMock.Object, hashingServiceMock.Object);
|
||||
|
||||
Assert.ThrowsAsync<NotFoundException>(() => sut.GetByIdAsync(id));
|
||||
repositoryMock.VerifyAll();
|
||||
hashingServiceMock.VerifyNoOtherCalls();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DeleteAsync_DeletesUser_WhenUserExists()
|
||||
{
|
||||
var repositoryMock = new Mock<IUserRepository>(MockBehavior.Strict);
|
||||
var hashingServiceMock = new Mock<IPasswordHashingService>(MockBehavior.Strict);
|
||||
var id = Guid.NewGuid();
|
||||
var user = CreateEntity(id);
|
||||
|
||||
repositoryMock.Setup(x => x.GetByIdAsync(id, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(user);
|
||||
repositoryMock.Setup(x => x.DeleteAsync(user, It.IsAny<CancellationToken>()))
|
||||
.Returns(Task.CompletedTask);
|
||||
|
||||
var sut = new UserService(repositoryMock.Object, hashingServiceMock.Object);
|
||||
|
||||
await sut.DeleteAsync(id);
|
||||
|
||||
repositoryMock.VerifyAll();
|
||||
hashingServiceMock.VerifyNoOtherCalls();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeleteAsync_ThrowsNotFound_WhenUserDoesNotExist()
|
||||
{
|
||||
var repositoryMock = new Mock<IUserRepository>(MockBehavior.Strict);
|
||||
var hashingServiceMock = new Mock<IPasswordHashingService>(MockBehavior.Strict);
|
||||
var id = Guid.NewGuid();
|
||||
|
||||
repositoryMock.Setup(x => x.GetByIdAsync(id, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((UserEntity?)null);
|
||||
|
||||
var sut = new UserService(repositoryMock.Object, hashingServiceMock.Object);
|
||||
|
||||
Assert.ThrowsAsync<NotFoundException>(() => sut.DeleteAsync(id));
|
||||
repositoryMock.VerifyAll();
|
||||
hashingServiceMock.VerifyNoOtherCalls();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ValidatePasswordAsync_ReturnsResult_WhenUserExists()
|
||||
{
|
||||
var repositoryMock = new Mock<IUserRepository>(MockBehavior.Strict);
|
||||
var hashingServiceMock = new Mock<IPasswordHashingService>(MockBehavior.Strict);
|
||||
var id = Guid.NewGuid();
|
||||
var user = CreateEntity(id);
|
||||
const string password = "AnyPassword!123";
|
||||
|
||||
repositoryMock.Setup(x => x.GetByIdAsync(id, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(user);
|
||||
hashingServiceMock.Setup(x => x.VerifyPassword(password, user.PasswordHash, user.PasswordSalt))
|
||||
.Returns(true);
|
||||
|
||||
var sut = new UserService(repositoryMock.Object, hashingServiceMock.Object);
|
||||
|
||||
var result = await sut.ValidatePasswordAsync(id, password);
|
||||
|
||||
Assert.That(result, Is.True);
|
||||
repositoryMock.VerifyAll();
|
||||
hashingServiceMock.VerifyAll();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ValidatePasswordAsync_ThrowsNotFound_WhenUserDoesNotExist()
|
||||
{
|
||||
var repositoryMock = new Mock<IUserRepository>(MockBehavior.Strict);
|
||||
var hashingServiceMock = new Mock<IPasswordHashingService>(MockBehavior.Strict);
|
||||
var id = Guid.NewGuid();
|
||||
|
||||
repositoryMock.Setup(x => x.GetByIdAsync(id, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((UserEntity?)null);
|
||||
|
||||
var sut = new UserService(repositoryMock.Object, hashingServiceMock.Object);
|
||||
|
||||
Assert.ThrowsAsync<NotFoundException>(() => sut.ValidatePasswordAsync(id, "AnyPassword!123"));
|
||||
repositoryMock.VerifyAll();
|
||||
hashingServiceMock.VerifyNoOtherCalls();
|
||||
}
|
||||
|
||||
private static CreateUserDto CreateRequest()
|
||||
{
|
||||
return new CreateUserDto
|
||||
{
|
||||
UserName = " new-user ",
|
||||
FullName = " New User ",
|
||||
Email = " new.user@example.com ",
|
||||
MobileNumber = " +38640123456 ",
|
||||
Language = " en ",
|
||||
Culture = " en-US ",
|
||||
Password = "ValidPassword!123"
|
||||
};
|
||||
}
|
||||
|
||||
private static UpdateUserDto CreateUpdateRequest(string? password)
|
||||
{
|
||||
return new UpdateUserDto
|
||||
{
|
||||
UserName = "updated-user",
|
||||
FullName = "Updated User",
|
||||
Email = "updated.user@example.com",
|
||||
MobileNumber = "+38640999888",
|
||||
Language = "en",
|
||||
Culture = "en-US",
|
||||
Password = password
|
||||
};
|
||||
}
|
||||
|
||||
private static UserEntity CreateEntity(Guid? id = null)
|
||||
{
|
||||
return new UserEntity
|
||||
{
|
||||
Id = id ?? Guid.NewGuid(),
|
||||
UserName = "existing-user",
|
||||
FullName = "Existing User",
|
||||
Email = "existing@example.com",
|
||||
MobileNumber = "+38640111222",
|
||||
Language = "en",
|
||||
Culture = "en-US",
|
||||
PasswordHash = "hash",
|
||||
PasswordSalt = "salt"
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user