2 Commits

9 changed files with 2 additions and 1089 deletions

View File

@@ -1,29 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\API\API.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>
</Project>

View File

@@ -1,184 +0,0 @@
using API.Controllers;
using API.Models.Internal.Altersgruppen;
using API.Repository.AgeGroupRepo;
using Microsoft.AspNetCore.Mvc;
using Moq;
namespace API.Tests.Controllers;
public class AgeGroupControllerTests
{
private readonly Mock<IAgeGroupService> _mockService;
private readonly AgeGroupController _controller;
public AgeGroupControllerTests()
{
_mockService = new Mock<IAgeGroupService>();
_controller = new AgeGroupController(_mockService.Object);
}
[Fact]
public async Task GetAll_ReturnsOkWithAllGroups()
{
// Arrange
var groups = new List<AltersGruppe>
{
new AltersGruppe { Id = "1", Name = "U10", StartingAge = 8, EndingAge = 10 },
new AltersGruppe { Id = "2", Name = "U12", StartingAge = 10, EndingAge = 12 }
};
_mockService.Setup(s => s.GetAllAsync()).ReturnsAsync(groups);
// Act
var result = await _controller.GetAll();
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
var returnedGroups = Assert.IsType<List<AltersGruppe>>(okResult.Value);
Assert.Equal(2, returnedGroups.Count);
}
[Fact]
public async Task GetAll_EmptyList_ReturnsOkWithEmptyList()
{
// Arrange
_mockService.Setup(s => s.GetAllAsync()).ReturnsAsync(new List<AltersGruppe>());
// Act
var result = await _controller.GetAll();
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
var returnedGroups = Assert.IsType<List<AltersGruppe>>(okResult.Value);
Assert.Empty(returnedGroups);
}
[Fact]
public async Task GetOne_ExistingId_ReturnsOkWithGroup()
{
// Arrange
var group = new AltersGruppe { Id = "123", Name = "U14", StartingAge = 12, EndingAge = 14 };
_mockService.Setup(s => s.GetAsync("123")).ReturnsAsync(group);
// Act
var result = await _controller.GetOne("123");
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
var returnedGroup = Assert.IsType<AltersGruppe>(okResult.Value);
Assert.Equal("U14", returnedGroup.Name);
}
[Fact]
public async Task GetOne_NonExistingId_ReturnsNotFound()
{
// Arrange
_mockService.Setup(s => s.GetAsync("nonexistent")).ReturnsAsync((AltersGruppe?)null);
// Act
var result = await _controller.GetOne("nonexistent");
// Assert
Assert.IsType<NotFoundResult>(result);
}
[Fact]
public async Task Create_ValidGroup_ReturnsCreatedAtAction()
{
// Arrange
var ingoingGroup = new AltersGruppeIngoing { Name = "U16", StartingAge = 14, EndingAge = 16 };
var createdGroup = new AltersGruppe { Id = "new-id", Name = "U16", StartingAge = 14, EndingAge = 16 };
_mockService.Setup(s => s.CreateAsync(It.IsAny<AltersGruppe>())).ReturnsAsync(createdGroup);
// Act
var result = await _controller.Create(ingoingGroup);
// Assert
var createdResult = Assert.IsType<CreatedAtActionResult>(result);
Assert.Equal(nameof(AgeGroupController.GetOne), createdResult.ActionName);
var returnedGroup = Assert.IsType<AltersGruppe>(createdResult.Value);
Assert.Equal("U16", returnedGroup.Name);
Assert.Equal("new-id", createdResult.RouteValues?["Id"]);
}
[Fact]
public async Task Update_ExistingGroup_ReturnsOkWithUpdatedGroup()
{
// Arrange
var ingoingGroup = new AltersGruppeIngoing { Name = "U16 Updated", StartingAge = 15, EndingAge = 16 };
var updatedGroup = new AltersGruppe { Id = "123", Name = "U16 Updated", StartingAge = 15, EndingAge = 16 };
_mockService.Setup(s => s.UpdateAsync("123", It.IsAny<AltersGruppe>())).ReturnsAsync(updatedGroup);
// Act
var result = await _controller.Update("123", ingoingGroup);
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
var returnedGroup = Assert.IsType<AltersGruppe>(okResult.Value);
Assert.Equal("U16 Updated", returnedGroup.Name);
Assert.Equal(15, returnedGroup.StartingAge);
}
[Fact]
public async Task Update_NonExistingGroup_ReturnsNotFound()
{
// Arrange
var ingoingGroup = new AltersGruppeIngoing { Name = "U16 Updated", StartingAge = 15, EndingAge = 16 };
_mockService.Setup(s => s.UpdateAsync("nonexistent", It.IsAny<AltersGruppe>())).ReturnsAsync((AltersGruppe?)null);
// Act
var result = await _controller.Update("nonexistent", ingoingGroup);
// Assert
Assert.IsType<NotFoundResult>(result);
}
[Fact]
public async Task Delete_ExistingGroup_ReturnsNoContent()
{
// Arrange
var group = new AltersGruppe { Id = "123", Name = "U18", StartingAge = 16, EndingAge = 18 };
_mockService.Setup(s => s.DeleteAsync("123")).ReturnsAsync(group);
// Act
var result = await _controller.Delete("123");
// Assert
Assert.IsType<NoContentResult>(result);
}
[Fact]
public async Task Delete_NonExistingGroup_ReturnsNotFound()
{
// Arrange
_mockService.Setup(s => s.DeleteAsync("nonexistent")).ReturnsAsync((AltersGruppe?)null);
// Act
var result = await _controller.Delete("nonexistent");
// Assert
Assert.IsType<NotFoundResult>(result);
}
[Fact]
public async Task Create_ServiceIsCalled_WithCorrectParameters()
{
// Arrange
var ingoingGroup = new AltersGruppeIngoing { Name = "U20", StartingAge = 18, EndingAge = 20 };
var createdGroup = new AltersGruppe { Id = "new-id", Name = "U20", StartingAge = 18, EndingAge = 20 };
_mockService.Setup(s => s.CreateAsync(It.IsAny<AltersGruppe>())).ReturnsAsync(createdGroup);
// Act
await _controller.Create(ingoingGroup);
// Assert
_mockService.Verify(s => s.CreateAsync(It.Is<AltersGruppe>(g =>
g.Name == "U20" &&
g.StartingAge == 18 &&
g.EndingAge == 20
)), Times.Once);
}
}

View File

@@ -1,118 +0,0 @@
using API.Models.Internal.Altersgruppen;
namespace API.Tests.Mappers;
public class AltersgruppeMapperTests
{
[Fact]
public void ToInternalFromIngoing_MapsAllProperties()
{
// Arrange
var ingoing = new AltersGruppeIngoing
{
Name = "U14",
StartingAge = 12,
EndingAge = 14
};
// Act
var result = ingoing.ToInternalFromIngoing();
// Assert
Assert.NotNull(result);
Assert.Equal("U14", result.Name);
Assert.Equal(12, result.StartingAge);
Assert.Equal(14, result.EndingAge);
}
[Fact]
public void ToInternalFromIngoing_GeneratesNewId()
{
// Arrange
var ingoing = new AltersGruppeIngoing
{
Name = "U16",
StartingAge = 14,
EndingAge = 16
};
// Act
var result = ingoing.ToInternalFromIngoing();
// Assert
Assert.NotNull(result.Id);
Assert.NotEmpty(result.Id);
}
[Fact]
public void ToInternalFromIngoing_GeneratesUniqueIds()
{
// Arrange
var ingoing1 = new AltersGruppeIngoing { Name = "U10", StartingAge = 8, EndingAge = 10 };
var ingoing2 = new AltersGruppeIngoing { Name = "U12", StartingAge = 10, EndingAge = 12 };
// Act
var result1 = ingoing1.ToInternalFromIngoing();
var result2 = ingoing2.ToInternalFromIngoing();
// Assert
Assert.NotEqual(result1.Id, result2.Id);
}
[Fact]
public void ToInternalFromIngoing_WithZeroAges_MapsCorrectly()
{
// Arrange
var ingoing = new AltersGruppeIngoing
{
Name = "Beginners",
StartingAge = 0,
EndingAge = 0
};
// Act
var result = ingoing.ToInternalFromIngoing();
// Assert
Assert.Equal(0, result.StartingAge);
Assert.Equal(0, result.EndingAge);
}
[Fact]
public void ToInternalFromIngoing_WithNegativeAges_MapsCorrectly()
{
// Arrange - testing edge case, though business logic might not allow this
var ingoing = new AltersGruppeIngoing
{
Name = "Invalid",
StartingAge = -1,
EndingAge = -5
};
// Act
var result = ingoing.ToInternalFromIngoing();
// Assert
Assert.Equal(-1, result.StartingAge);
Assert.Equal(-5, result.EndingAge);
}
[Fact]
public void ToInternalFromIngoing_WithLargeAges_MapsCorrectly()
{
// Arrange
var ingoing = new AltersGruppeIngoing
{
Name = "Seniors",
StartingAge = 60,
EndingAge = 100
};
// Act
var result = ingoing.ToInternalFromIngoing();
// Assert
Assert.Equal(60, result.StartingAge);
Assert.Equal(100, result.EndingAge);
}
}

View File

@@ -1,123 +0,0 @@
using API.Models.Internal.User;
namespace API.Tests.Mappers;
public class RegistrationKeyMapperTests
{
[Fact]
public void ToInternalFromIngoing_MapsLinkedRole()
{
// Arrange
var ingoing = new RegistrationKeyIngoing
{
LinkedRole = "Admin"
};
// Act
var result = ingoing.ToInternalFromIngoing();
// Assert
Assert.NotNull(result);
Assert.Equal("Admin", result.LinkedRole);
}
[Fact]
public void ToInternalFromIngoing_NullLinkedRole_MapsCorrectly()
{
// Arrange
var ingoing = new RegistrationKeyIngoing
{
LinkedRole = null
};
// Act
var result = ingoing.ToInternalFromIngoing();
// Assert
Assert.NotNull(result);
Assert.Null(result.LinkedRole);
}
[Fact]
public void ToInternalFromIngoing_GeneratesNewId()
{
// Arrange
var ingoing = new RegistrationKeyIngoing
{
LinkedRole = "User"
};
// Act
var result = ingoing.ToInternalFromIngoing();
// Assert
Assert.NotNull(result.Id);
Assert.NotEmpty(result.Id);
}
[Fact]
public void ToInternalFromIngoing_GeneratesUniqueIds()
{
// Arrange
var ingoing1 = new RegistrationKeyIngoing { LinkedRole = "Admin" };
var ingoing2 = new RegistrationKeyIngoing { LinkedRole = "User" };
// Act
var result1 = ingoing1.ToInternalFromIngoing();
var result2 = ingoing2.ToInternalFromIngoing();
// Assert
Assert.NotEqual(result1.Id, result2.Id);
}
[Fact]
public void ToInternalFromIngoing_SetsCreatedDate()
{
// Arrange
var ingoing = new RegistrationKeyIngoing
{
LinkedRole = "Moderator"
};
var beforeCreation = DateTime.UtcNow;
// Act
var result = ingoing.ToInternalFromIngoing();
// Assert
var afterCreation = DateTime.UtcNow;
Assert.True(result.Created >= beforeCreation.AddSeconds(-1));
Assert.True(result.Created <= afterCreation.AddSeconds(1));
}
[Fact]
public void ToInternalFromIngoing_EmptyLinkedRole_MapsCorrectly()
{
// Arrange
var ingoing = new RegistrationKeyIngoing
{
LinkedRole = ""
};
// Act
var result = ingoing.ToInternalFromIngoing();
// Assert
Assert.Equal("", result.LinkedRole);
}
[Fact]
public void ToInternalFromIngoing_WhitespaceLinkedRole_MapsCorrectly()
{
// Arrange
var ingoing = new RegistrationKeyIngoing
{
LinkedRole = " "
};
// Act
var result = ingoing.ToInternalFromIngoing();
// Assert
Assert.Equal(" ", result.LinkedRole);
}
}

View File

@@ -1,169 +0,0 @@
using API.Database;
using API.Models.Internal.Altersgruppen;
using API.Repository.AgeGroupRepo;
using Microsoft.EntityFrameworkCore;
namespace API.Tests.Services;
public class AgeGroupServiceTests : IDisposable
{
private readonly ApplicationDbContext _context;
private readonly AgeGroupService _service;
public AgeGroupServiceTests()
{
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
.Options;
_context = new ApplicationDbContext(options);
_service = new AgeGroupService(_context);
}
public void Dispose()
{
_context.Database.EnsureDeleted();
_context.Dispose();
}
[Fact]
public async Task GetAllAsync_EmptyDatabase_ReturnsEmptyList()
{
// Act
var result = await _service.GetAllAsync();
// Assert
Assert.NotNull(result);
Assert.Empty(result);
}
[Fact]
public async Task GetAllAsync_WithData_ReturnsAllGroups()
{
// Arrange
var group1 = new AltersGruppe { Name = "U10", StartingAge = 8, EndingAge = 10 };
var group2 = new AltersGruppe { Name = "U12", StartingAge = 10, EndingAge = 12 };
await _context.Altersgruppen.AddRangeAsync(group1, group2);
await _context.SaveChangesAsync();
// Act
var result = await _service.GetAllAsync();
// Assert
Assert.Equal(2, result.Count);
Assert.Contains(result, g => g.Name == "U10");
Assert.Contains(result, g => g.Name == "U12");
}
[Fact]
public async Task GetAsync_ExistingId_ReturnsGroup()
{
// Arrange
var group = new AltersGruppe { Name = "U14", StartingAge = 12, EndingAge = 14 };
await _context.Altersgruppen.AddAsync(group);
await _context.SaveChangesAsync();
// Act
var result = await _service.GetAsync(group.Id);
// Assert
Assert.NotNull(result);
Assert.Equal("U14", result.Name);
Assert.Equal(12, result.StartingAge);
Assert.Equal(14, result.EndingAge);
}
[Fact]
public async Task GetAsync_NonExistingId_ReturnsNull()
{
// Act
var result = await _service.GetAsync("nonexistent-id");
// Assert
Assert.Null(result);
}
[Fact]
public async Task CreateAsync_ValidGroup_AddsToDatabase()
{
// Arrange
var newGroup = new AltersGruppe { Name = "U16", StartingAge = 14, EndingAge = 16 };
// Act
var result = await _service.CreateAsync(newGroup);
// Assert
Assert.NotNull(result);
Assert.Equal("U16", result.Name);
var dbGroup = await _context.Altersgruppen.FindAsync(result.Id);
Assert.NotNull(dbGroup);
Assert.Equal("U16", dbGroup.Name);
}
[Fact]
public async Task UpdateAsync_ExistingGroup_UpdatesProperties()
{
// Arrange
var group = new AltersGruppe { Name = "U18", StartingAge = 16, EndingAge = 18 };
await _context.Altersgruppen.AddAsync(group);
await _context.SaveChangesAsync();
var updatedGroup = new AltersGruppe { Name = "U18 Updated", StartingAge = 15, EndingAge = 18 };
// Act
var result = await _service.UpdateAsync(group.Id, updatedGroup);
// Assert
Assert.NotNull(result);
Assert.Equal("U18 Updated", result.Name);
Assert.Equal(15, result.StartingAge);
Assert.Equal(18, result.EndingAge);
var dbGroup = await _context.Altersgruppen.FindAsync(group.Id);
Assert.NotNull(dbGroup);
Assert.Equal("U18 Updated", dbGroup.Name);
}
[Fact]
public async Task UpdateAsync_NonExistingGroup_ReturnsNull()
{
// Arrange
var updatedGroup = new AltersGruppe { Name = "U18 Updated", StartingAge = 15, EndingAge = 18 };
// Act
var result = await _service.UpdateAsync("nonexistent-id", updatedGroup);
// Assert
Assert.Null(result);
}
[Fact]
public async Task DeleteAsync_ExistingGroup_RemovesFromDatabase()
{
// Arrange
var group = new AltersGruppe { Name = "U20", StartingAge = 18, EndingAge = 20 };
await _context.Altersgruppen.AddAsync(group);
await _context.SaveChangesAsync();
// Act
var result = await _service.DeleteAsync(group.Id);
// Assert
Assert.NotNull(result);
Assert.Equal("U20", result.Name);
var dbGroup = await _context.Altersgruppen.FindAsync(group.Id);
Assert.Null(dbGroup);
}
[Fact]
public async Task DeleteAsync_NonExistingGroup_ReturnsNull()
{
// Act
var result = await _service.DeleteAsync("nonexistent-id");
// Assert
Assert.Null(result);
}
}

View File

@@ -1,214 +0,0 @@
using System.Net;
using System.Text.Json;
using API.Models.Outgoing;
using API.Services;
using Moq;
using Moq.Protected;
namespace API.Tests.Services;
public class PlunkEmailSenderTests
{
private const string TestSecretKey = "test-secret-key";
private const string PlunkApiUrl = "https://api.useplunk.com/v1/send";
private static HttpClient CreateMockHttpClient(HttpStatusCode statusCode, string responseContent = "{}")
{
var mockHandler = new Mock<HttpMessageHandler>();
mockHandler
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{
StatusCode = statusCode,
Content = new StringContent(responseContent)
});
return new HttpClient(mockHandler.Object);
}
private static (HttpClient client, Mock<HttpMessageHandler> handler) CreateMockHttpClientWithHandler(
HttpStatusCode statusCode, string responseContent = "{}")
{
var mockHandler = new Mock<HttpMessageHandler>();
mockHandler
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{
StatusCode = statusCode,
Content = new StringContent(responseContent)
});
return (new HttpClient(mockHandler.Object), mockHandler);
}
[Fact]
public async Task SendEmailAsync_SuccessfulSend_DoesNotThrow()
{
// Arrange
var httpClient = CreateMockHttpClient(HttpStatusCode.OK);
var emailSender = new PlunkEmailSender(httpClient, TestSecretKey);
// Act & Assert - should not throw
await emailSender.SendEmailAsync("test@example.com", "Test Subject", "<p>Test Body</p>");
}
[Fact]
public async Task SendEmailAsync_ApiReturnsError_ThrowsException()
{
// Arrange
var errorMessage = "Invalid API key";
var httpClient = CreateMockHttpClient(HttpStatusCode.Unauthorized, errorMessage);
var emailSender = new PlunkEmailSender(httpClient, TestSecretKey);
// Act & Assert
var exception = await Assert.ThrowsAsync<Exception>(() =>
emailSender.SendEmailAsync("test@example.com", "Test Subject", "<p>Test Body</p>"));
Assert.Contains("Fehler beim Senden der E-Mail über Plunk", exception.Message);
Assert.Contains(errorMessage, exception.Message);
}
[Fact]
public async Task SendEmailAsync_ServerError_ThrowsException()
{
// Arrange
var httpClient = CreateMockHttpClient(HttpStatusCode.InternalServerError, "Server error");
var emailSender = new PlunkEmailSender(httpClient, TestSecretKey);
// Act & Assert
await Assert.ThrowsAsync<Exception>(() =>
emailSender.SendEmailAsync("test@example.com", "Test Subject", "<p>Test Body</p>"));
}
[Fact]
public async Task SendEmailAsync_BadRequest_ThrowsException()
{
// Arrange
var httpClient = CreateMockHttpClient(HttpStatusCode.BadRequest, "Invalid request");
var emailSender = new PlunkEmailSender(httpClient, TestSecretKey);
// Act & Assert
await Assert.ThrowsAsync<Exception>(() =>
emailSender.SendEmailAsync("test@example.com", "Test Subject", "<p>Test Body</p>"));
}
[Fact]
public async Task SendEmailAsync_SendsCorrectPayload()
{
// Arrange
var mockHandler = new Mock<HttpMessageHandler>();
HttpRequestMessage? capturedRequest = null;
mockHandler
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.Callback<HttpRequestMessage, CancellationToken>((request, _) => capturedRequest = request)
.ReturnsAsync(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent("{}")
});
var httpClient = new HttpClient(mockHandler.Object);
var emailSender = new PlunkEmailSender(httpClient, TestSecretKey);
// Act
await emailSender.SendEmailAsync("recipient@example.com", "My Subject", "<h1>Hello</h1>");
// Assert
Assert.NotNull(capturedRequest);
Assert.Equal(HttpMethod.Post, capturedRequest.Method);
Assert.Equal(PlunkApiUrl, capturedRequest.RequestUri?.ToString());
var requestContent = await capturedRequest.Content!.ReadAsStringAsync();
var payload = JsonSerializer.Deserialize<PlunkEmailDto>(requestContent, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
Assert.NotNull(payload);
Assert.Equal("recipient@example.com", payload.To);
Assert.Equal("My Subject", payload.Subject);
Assert.Equal("<h1>Hello</h1>", payload.Body);
}
[Fact]
public async Task SendEmailAsync_SendsCorrectAuthorizationHeader()
{
// Arrange
var mockHandler = new Mock<HttpMessageHandler>();
HttpRequestMessage? capturedRequest = null;
mockHandler
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.Callback<HttpRequestMessage, CancellationToken>((request, _) => capturedRequest = request)
.ReturnsAsync(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent("{}")
});
var httpClient = new HttpClient(mockHandler.Object);
var emailSender = new PlunkEmailSender(httpClient, "my-secret-api-key");
// Act
await emailSender.SendEmailAsync("test@example.com", "Subject", "Body");
// Assert
Assert.NotNull(capturedRequest);
var authHeader = httpClient.DefaultRequestHeaders.Authorization;
Assert.NotNull(authHeader);
Assert.Equal("Bearer", authHeader.Scheme);
Assert.Equal("my-secret-api-key", authHeader.Parameter);
}
[Fact]
public async Task SendEmailAsync_SendsCorrectContentType()
{
// Arrange
var mockHandler = new Mock<HttpMessageHandler>();
HttpRequestMessage? capturedRequest = null;
mockHandler
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.Callback<HttpRequestMessage, CancellationToken>((request, _) => capturedRequest = request)
.ReturnsAsync(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent("{}")
});
var httpClient = new HttpClient(mockHandler.Object);
var emailSender = new PlunkEmailSender(httpClient, TestSecretKey);
// Act
await emailSender.SendEmailAsync("test@example.com", "Subject", "Body");
// Assert
Assert.NotNull(capturedRequest);
Assert.NotNull(capturedRequest.Content);
Assert.Equal("application/json", capturedRequest.Content.Headers.ContentType?.MediaType);
Assert.Equal("utf-8", capturedRequest.Content.Headers.ContentType?.CharSet);
}
}

View File

@@ -1,244 +0,0 @@
using API.Database;
using API.Models.Internal.User;
using API.Repository.RegistrationKeyRepo;
using Microsoft.EntityFrameworkCore;
namespace API.Tests.Services;
public class RegistrationKeyServiceTests : IDisposable
{
private readonly ApplicationDbContext _context;
private readonly RegistrationKeyService _service;
public RegistrationKeyServiceTests()
{
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
.Options;
_context = new ApplicationDbContext(options);
_service = new RegistrationKeyService(_context);
}
public void Dispose()
{
_context.Database.EnsureDeleted();
_context.Dispose();
}
[Fact]
public async Task GetAllAsync_EmptyDatabase_ReturnsEmptyList()
{
// Act
var result = await _service.GetAllAsync();
// Assert
Assert.NotNull(result);
Assert.Empty(result);
}
[Fact]
public async Task GetAllAsync_WithData_ReturnsAllKeys()
{
// Arrange
var key1 = new RegistrationKey { LinkedRole = "Admin" };
var key2 = new RegistrationKey { LinkedRole = "User" };
await _context.RegistrationKeys.AddRangeAsync(key1, key2);
await _context.SaveChangesAsync();
// Act
var result = await _service.GetAllAsync();
// Assert
Assert.Equal(2, result.Count);
Assert.Contains(result, k => k.LinkedRole == "Admin");
Assert.Contains(result, k => k.LinkedRole == "User");
}
[Fact]
public async Task GetAsync_ExistingId_ReturnsKey()
{
// Arrange
var key = new RegistrationKey { LinkedRole = "Moderator" };
await _context.RegistrationKeys.AddAsync(key);
await _context.SaveChangesAsync();
// Act
var result = await _service.GetAsync(key.Id);
// Assert
Assert.NotNull(result);
Assert.Equal("Moderator", result.LinkedRole);
}
[Fact]
public async Task GetAsync_NonExistingId_ReturnsNull()
{
// Act
var result = await _service.GetAsync("nonexistent-id");
// Assert
Assert.Null(result);
}
[Fact]
public async Task CreateAsync_ValidKey_AddsToDatabase()
{
// Arrange
var keyIngoing = new RegistrationKeyIngoing { LinkedRole = "Admin" };
// Act
var result = await _service.CreateAsync(keyIngoing);
// Assert
Assert.NotNull(result);
Assert.Equal("Admin", result.LinkedRole);
Assert.NotNull(result.Id);
var dbKey = await _context.RegistrationKeys.FindAsync(result.Id);
Assert.NotNull(dbKey);
Assert.Equal("Admin", dbKey.LinkedRole);
}
[Fact]
public async Task CreateAsync_NullRole_AddsToDatabase()
{
// Arrange
var keyIngoing = new RegistrationKeyIngoing { LinkedRole = null };
// Act
var result = await _service.CreateAsync(keyIngoing);
// Assert
Assert.NotNull(result);
Assert.Null(result.LinkedRole);
var dbKey = await _context.RegistrationKeys.FindAsync(result.Id);
Assert.NotNull(dbKey);
}
[Fact]
public async Task DeleteAsync_ExistingKey_RemovesFromDatabase()
{
// Arrange
var key = new RegistrationKey { LinkedRole = "ToDelete" };
await _context.RegistrationKeys.AddAsync(key);
await _context.SaveChangesAsync();
// Act
var result = await _service.DeleteAsync(key.Id);
// Assert
Assert.NotNull(result);
Assert.Equal("ToDelete", result.LinkedRole);
var dbKey = await _context.RegistrationKeys.FindAsync(key.Id);
Assert.Null(dbKey);
}
[Fact]
public async Task DeleteAsync_NonExistingKey_ReturnsNull()
{
// Act
var result = await _service.DeleteAsync("nonexistent-id");
// Assert
Assert.Null(result);
}
[Fact]
public async Task DeleteOldRegistrationKeysAsync_ZeroDays_ReturnsZero()
{
// Arrange
var key = new RegistrationKey { LinkedRole = "Old", Created = DateTime.UtcNow.AddDays(-10) };
await _context.RegistrationKeys.AddAsync(key);
await _context.SaveChangesAsync();
// Act
var result = await _service.DeleteOldRegistrationKeysAsync(0);
// Assert
Assert.Equal(0, result);
Assert.Single(await _context.RegistrationKeys.ToListAsync());
}
[Fact]
public async Task DeleteOldRegistrationKeysAsync_NegativeDays_ReturnsZero()
{
// Arrange
var key = new RegistrationKey { LinkedRole = "Old", Created = DateTime.UtcNow.AddDays(-10) };
await _context.RegistrationKeys.AddAsync(key);
await _context.SaveChangesAsync();
// Act
var result = await _service.DeleteOldRegistrationKeysAsync(-5);
// Assert
Assert.Equal(0, result);
Assert.Single(await _context.RegistrationKeys.ToListAsync());
}
[Fact]
public async Task DeleteOldRegistrationKeysAsync_NoOldKeys_ReturnsZero()
{
// Arrange
var key = new RegistrationKey { LinkedRole = "New", Created = DateTime.UtcNow };
await _context.RegistrationKeys.AddAsync(key);
await _context.SaveChangesAsync();
// Act
var result = await _service.DeleteOldRegistrationKeysAsync(7);
// Assert
Assert.Equal(0, result);
Assert.Single(await _context.RegistrationKeys.ToListAsync());
}
[Fact]
public async Task DeleteOldRegistrationKeysAsync_WithOldKeys_DeletesOldKeysOnly()
{
// Arrange
var oldKey1 = new RegistrationKey { LinkedRole = "Old1", Created = DateTime.UtcNow.AddDays(-10) };
var oldKey2 = new RegistrationKey { LinkedRole = "Old2", Created = DateTime.UtcNow.AddDays(-15) };
var newKey = new RegistrationKey { LinkedRole = "New", Created = DateTime.UtcNow.AddDays(-2) };
await _context.RegistrationKeys.AddRangeAsync(oldKey1, oldKey2, newKey);
await _context.SaveChangesAsync();
// Act
var result = await _service.DeleteOldRegistrationKeysAsync(7);
// Assert
Assert.Equal(2, result);
var remainingKeys = await _context.RegistrationKeys.ToListAsync();
Assert.Single(remainingKeys);
Assert.Equal("New", remainingKeys[0].LinkedRole);
}
[Fact]
public async Task DeleteOldRegistrationKeysAsync_ExactCutoffDate_KeyNotDeleted()
{
// Arrange - key created exactly at cutoff should NOT be deleted
var keyAtCutoff = new RegistrationKey { LinkedRole = "AtCutoff", Created = DateTime.UtcNow.AddDays(-7) };
await _context.RegistrationKeys.AddAsync(keyAtCutoff);
await _context.SaveChangesAsync();
// Act
var result = await _service.DeleteOldRegistrationKeysAsync(7);
// Assert - cutoff is < not <=, so exactly 7 days old should not be deleted
Assert.Equal(0, result);
Assert.Single(await _context.RegistrationKeys.ToListAsync());
}
[Fact]
public async Task DeleteOldRegistrationKeysAsync_EmptyDatabase_ReturnsZero()
{
// Act
var result = await _service.DeleteOldRegistrationKeysAsync(7);
// Assert
Assert.Equal(0, result);
}
}

View File

@@ -1,12 +1,10 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.14.36518.9 d17.14 VisualStudioVersion = 17.14.36518.9 d17.14
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "API", "API\API.csproj", "{98166726-DC3A-4D5B-889A-8B4428E28656}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "API", "API\API.csproj", "{98166726-DC3A-4D5B-889A-8B4428E28656}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "API.Tests", "API.Tests\API.Tests.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -17,10 +15,6 @@ Global
{98166726-DC3A-4D5B-889A-8B4428E28656}.Debug|Any CPU.Build.0 = Debug|Any CPU {98166726-DC3A-4D5B-889A-8B4428E28656}.Debug|Any CPU.Build.0 = Debug|Any CPU
{98166726-DC3A-4D5B-889A-8B4428E28656}.Release|Any CPU.ActiveCfg = Release|Any CPU {98166726-DC3A-4D5B-889A-8B4428E28656}.Release|Any CPU.ActiveCfg = Release|Any CPU
{98166726-DC3A-4D5B-889A-8B4428E28656}.Release|Any CPU.Build.0 = Release|Any CPU {98166726-DC3A-4D5B-889A-8B4428E28656}.Release|Any CPU.Build.0 = Release|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE