- Add API.Tests xUnit project with Moq and EF Core InMemory - Add AgeGroupService tests (CRUD operations, edge cases) - Add RegistrationKeyService tests (CRUD + DeleteOldRegistrationKeys) - Add AgeGroupController tests (all endpoints with mocked service) - Add PlunkEmailSender tests (HTTP client mocking, payload verification) - Add Mapper tests (AltersgruppeMapper, RegistrationKeyMapper) https://claude.ai/code/session_01Kv7Mp2c9FKsHEgQe4BoftH
215 lines
7.6 KiB
C#
215 lines
7.6 KiB
C#
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);
|
|
}
|
|
}
|