Neues Testprojekt SlipItIn.Server.Tests erstellt und in die Solution eingebunden. Unit- und Integrationstests für AuthController, DbSeeder, GameHub und GameService implementiert. TestDbHelper für InMemory-DbContexts und Testdaten hinzugefügt. Tests prüfen Erfolgs- und Fehlerfälle inkl. Validierungen, Fehlerbehandlung und DB-Zustände.
204 lines
6.8 KiB
C#
204 lines
6.8 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Configuration;
|
|
using SlipItIn.Server.Controllers;
|
|
using SlipItIn.Server.Data;
|
|
using SlipItIn.Shared.DTOs;
|
|
using SlipItIn.Shared.Models;
|
|
using System.IdentityModel.Tokens.Jwt;
|
|
using System.Security.Claims;
|
|
|
|
namespace SlipItIn.Server.Tests;
|
|
|
|
public class AuthControllerTests
|
|
{
|
|
private readonly IDbContextFactory<SlipItInDbContext> _factory = TestDbHelper.CreateFactory();
|
|
private readonly AuthController _sut;
|
|
|
|
public AuthControllerTests()
|
|
{
|
|
var config = new ConfigurationBuilder()
|
|
.AddInMemoryCollection(new Dictionary<string, string?>
|
|
{
|
|
["Jwt:Key"] = "TestKeyThatIsAtLeast32CharactersLong!!",
|
|
["Jwt:Issuer"] = "TestIssuer",
|
|
["Jwt:Audience"] = "TestAudience",
|
|
["Jwt:ExpirationMinutes"] = "60"
|
|
})
|
|
.Build();
|
|
_sut = new AuthController(_factory, config);
|
|
}
|
|
|
|
// ---------- Register ----------
|
|
|
|
[Fact]
|
|
public async Task Register_ReturnsOk_WithTokenAndUserData()
|
|
{
|
|
var result = await _sut.Register(new RegisterRequestDto
|
|
{
|
|
Username = " Alice ",
|
|
Email = " ALICE@Test.Local ",
|
|
Password = "Secret123!"
|
|
});
|
|
|
|
var ok = Assert.IsType<OkObjectResult>(result.Result);
|
|
var dto = Assert.IsType<AuthResponseDto>(ok.Value);
|
|
Assert.Equal("Alice", dto.Username); // getrimmt
|
|
Assert.Equal("alice@test.local", dto.Email); // getrimmt + lowercase
|
|
Assert.True(dto.UserId > 0);
|
|
Assert.False(string.IsNullOrWhiteSpace(dto.Token));
|
|
Assert.True(dto.ExpiresAtUtc > DateTime.UtcNow);
|
|
|
|
// Token enthält die erwarteten Claims und ist valide lesbar
|
|
var token = new JwtSecurityTokenHandler().ReadJwtToken(dto.Token);
|
|
Assert.Equal("TestIssuer", token.Issuer);
|
|
Assert.Contains("TestAudience", token.Audiences);
|
|
Assert.Equal(dto.UserId.ToString(), token.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("", "a@b.c", "pw")]
|
|
[InlineData("user", "", "pw")]
|
|
[InlineData("user", "a@b.c", "")]
|
|
[InlineData(" ", "a@b.c", "pw")]
|
|
public async Task Register_ReturnsBadRequest_WhenFieldsMissing(string username, string email, string password)
|
|
{
|
|
var result = await _sut.Register(new RegisterRequestDto { Username = username, Email = email, Password = password });
|
|
|
|
Assert.IsType<BadRequestObjectResult>(result.Result);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Register_ReturnsConflict_WhenEmailExists_CaseInsensitive()
|
|
{
|
|
using var db = _factory.CreateDbContext();
|
|
TestDbHelper.SeedUser(db, "existing", "alice@test.local");
|
|
|
|
var result = await _sut.Register(new RegisterRequestDto
|
|
{
|
|
Username = "newuser",
|
|
Email = "ALICE@TEST.LOCAL",
|
|
Password = "Secret123!"
|
|
});
|
|
|
|
Assert.IsType<ConflictObjectResult>(result.Result);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Register_ReturnsConflict_WhenUsernameExists_CaseInsensitive()
|
|
{
|
|
using var db = _factory.CreateDbContext();
|
|
TestDbHelper.SeedUser(db, "alice", "other@test.local");
|
|
|
|
var result = await _sut.Register(new RegisterRequestDto
|
|
{
|
|
Username = "ALICE",
|
|
Email = "new@test.local",
|
|
Password = "Secret123!"
|
|
});
|
|
|
|
Assert.IsType<ConflictObjectResult>(result.Result);
|
|
}
|
|
|
|
// ---------- Login ----------
|
|
|
|
[Fact]
|
|
public async Task Login_ReturnsOk_WithValidCredentials()
|
|
{
|
|
using var db = _factory.CreateDbContext();
|
|
db.Users.Add(new User
|
|
{
|
|
Username = "bob",
|
|
Email = "bob@test.local",
|
|
PasswordHash = BCrypt.Net.BCrypt.HashPassword("Secret123!")
|
|
});
|
|
await db.SaveChangesAsync();
|
|
|
|
var result = await _sut.Login(new LoginRequestDto { Email = " BOB@test.local ", Password = "Secret123!" });
|
|
|
|
var ok = Assert.IsType<OkObjectResult>(result.Result);
|
|
var dto = Assert.IsType<AuthResponseDto>(ok.Value);
|
|
Assert.Equal("bob", dto.Username);
|
|
Assert.False(string.IsNullOrWhiteSpace(dto.Token));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("", "pw")]
|
|
[InlineData("a@b.c", "")]
|
|
public async Task Login_ReturnsBadRequest_WhenFieldsMissing(string email, string password)
|
|
{
|
|
var result = await _sut.Login(new LoginRequestDto { Email = email, Password = password });
|
|
|
|
Assert.IsType<BadRequestObjectResult>(result.Result);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Login_ReturnsUnauthorized_WhenUserNotFound()
|
|
{
|
|
var result = await _sut.Login(new LoginRequestDto { Email = "ghost@test.local", Password = "Secret123!" });
|
|
|
|
Assert.IsType<UnauthorizedObjectResult>(result.Result);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Login_ReturnsUnauthorized_WhenPasswordWrong()
|
|
{
|
|
using var db = _factory.CreateDbContext();
|
|
db.Users.Add(new User
|
|
{
|
|
Username = "bob",
|
|
Email = "bob@test.local",
|
|
PasswordHash = BCrypt.Net.BCrypt.HashPassword("CorrectPassword")
|
|
});
|
|
await db.SaveChangesAsync();
|
|
|
|
var result = await _sut.Login(new LoginRequestDto { Email = "bob@test.local", Password = "WrongPassword" });
|
|
|
|
Assert.IsType<UnauthorizedObjectResult>(result.Result);
|
|
}
|
|
|
|
// ---------- Me ----------
|
|
|
|
[Fact]
|
|
public void Me_ReturnsUserData_FromClaims()
|
|
{
|
|
var identity = new ClaimsIdentity([
|
|
new Claim(ClaimTypes.NameIdentifier, "42"),
|
|
new Claim(ClaimTypes.Name, "alice"),
|
|
new Claim(ClaimTypes.Email, "alice@test.local")
|
|
], "TestAuth");
|
|
_sut.ControllerContext = new ControllerContext
|
|
{
|
|
HttpContext = new Microsoft.AspNetCore.Http.DefaultHttpContext
|
|
{
|
|
User = new ClaimsPrincipal(identity)
|
|
}
|
|
};
|
|
|
|
var result = _sut.Me();
|
|
|
|
var ok = Assert.IsType<OkObjectResult>(result.Result);
|
|
var value = ok.Value!;
|
|
Assert.Equal(42, (int)value.GetType().GetProperty("UserId")!.GetValue(value)!);
|
|
Assert.Equal("alice", (string)value.GetType().GetProperty("Username")!.GetValue(value)!);
|
|
Assert.Equal("alice@test.local", (string)value.GetType().GetProperty("Email")!.GetValue(value)!);
|
|
}
|
|
|
|
[Fact]
|
|
public void Me_ReturnsUnauthorized_WhenNameIdentifierClaimMissing()
|
|
{
|
|
var identity = new ClaimsIdentity([new Claim(ClaimTypes.Name, "alice")], "TestAuth");
|
|
_sut.ControllerContext = new ControllerContext
|
|
{
|
|
HttpContext = new Microsoft.AspNetCore.Http.DefaultHttpContext
|
|
{
|
|
User = new ClaimsPrincipal(identity)
|
|
}
|
|
};
|
|
|
|
var result = _sut.Me();
|
|
|
|
Assert.IsType<UnauthorizedResult>(result.Result);
|
|
}
|
|
}
|