Add MediatorExtensions tests and refactor CreateEnvelopeCommand
Introduce MediatorExtensionsTests to cover SendOrThrowAsync and SendOrNotFoundAsync extension methods for IMediator, including edge cases and cancellation. Refactor CreateEnvelopeCommand in Fake.cs to use Authorize(userId) instead of setting UserId directly. Add test stubs for IMediator and IRequest to support isolated testing.
This commit is contained in:
287
EnvelopeGenerator.Tests/Application/MediatorExtensionsTests.cs
Normal file
287
EnvelopeGenerator.Tests/Application/MediatorExtensionsTests.cs
Normal file
@@ -0,0 +1,287 @@
|
||||
using DigitalData.Core.Exceptions;
|
||||
using EnvelopeGenerator.Application.Common.Extensions;
|
||||
using MediatR;
|
||||
|
||||
namespace EnvelopeGenerator.Tests.Application;
|
||||
|
||||
[TestFixture]
|
||||
public class MediatorExtensionsTests
|
||||
{
|
||||
#region Stub infrastructure
|
||||
|
||||
private sealed class StubRequest<TResponse> : IRequest<TResponse?> { }
|
||||
|
||||
/// <summary>
|
||||
/// Minimal <see cref="IMediator"/> stub that returns a pre-configured response for any <see cref="Send"/> call.
|
||||
/// </summary>
|
||||
private sealed class StubMediator : IMediator
|
||||
{
|
||||
private readonly object? _response;
|
||||
|
||||
public StubMediator(object? response) => _response = response;
|
||||
|
||||
public Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return Task.FromResult((TResponse)_response!);
|
||||
}
|
||||
|
||||
public Task Send<TRequest>(TRequest request, CancellationToken cancellationToken = default) where TRequest : IRequest
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<object?> Send(object request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return Task.FromResult(_response);
|
||||
}
|
||||
|
||||
public IAsyncEnumerable<TResponse> CreateStream<TResponse>(IStreamRequest<TResponse> request, CancellationToken cancellationToken = default)
|
||||
=> throw new NotImplementedException();
|
||||
|
||||
public IAsyncEnumerable<object?> CreateStream(object request, CancellationToken cancellationToken = default)
|
||||
=> throw new NotImplementedException();
|
||||
|
||||
public Task Publish(object notification, CancellationToken cancellationToken = default)
|
||||
=> Task.CompletedTask;
|
||||
|
||||
public Task Publish<TNotification>(TNotification notification, CancellationToken cancellationToken = default) where TNotification : INotification
|
||||
=> Task.CompletedTask;
|
||||
}
|
||||
|
||||
private static IMediator CreateMediator<T>(T? response) => new StubMediator(response);
|
||||
|
||||
#endregion
|
||||
|
||||
#region SendOrThrowAsync — non-null scalar
|
||||
|
||||
[Test]
|
||||
public async Task SendOrThrowAsync_WithNonNullResponse_ReturnsResponse()
|
||||
{
|
||||
var mediator = CreateMediator<string>("hello");
|
||||
var request = new StubRequest<string?>();
|
||||
|
||||
var result = await mediator.SendOrThrowAsync(request, () => new InvalidOperationException());
|
||||
|
||||
Assert.That(result, Is.EqualTo("hello"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SendOrThrowAsync — null response
|
||||
|
||||
[Test]
|
||||
public void SendOrThrowAsync_WithNullResponse_ThrowsCustomException()
|
||||
{
|
||||
var mediator = CreateMediator<string>(null);
|
||||
var request = new StubRequest<string?>();
|
||||
|
||||
var ex = Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => mediator.SendOrThrowAsync(request, () => new InvalidOperationException("custom")));
|
||||
|
||||
Assert.That(ex!.Message, Is.EqualTo("custom"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SendOrThrowAsync — empty collection
|
||||
|
||||
[Test]
|
||||
public void SendOrThrowAsync_WithEmptyList_ThrowsCustomException()
|
||||
{
|
||||
var mediator = CreateMediator<List<string>>(new List<string>());
|
||||
var request = new StubRequest<List<string>?>();
|
||||
|
||||
Assert.ThrowsAsync<ArgumentException>(
|
||||
() => mediator.SendOrThrowAsync(request, () => new ArgumentException("empty")));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SendOrThrowAsync — non-empty collection
|
||||
|
||||
[Test]
|
||||
public async Task SendOrThrowAsync_WithNonEmptyList_ReturnsResponse()
|
||||
{
|
||||
var expected = new List<int> { 1, 2 };
|
||||
var mediator = CreateMediator<List<int>>(expected);
|
||||
var request = new StubRequest<List<int>?>();
|
||||
|
||||
var result = await mediator.SendOrThrowAsync(request, () => new InvalidOperationException());
|
||||
|
||||
Assert.That(result, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SendOrThrowAsync — string edge case (string implements IEnumerable)
|
||||
|
||||
[Test]
|
||||
public async Task SendOrThrowAsync_WithEmptyString_ReturnsEmptyString()
|
||||
{
|
||||
var mediator = CreateMediator<string>("");
|
||||
var request = new StubRequest<string?>();
|
||||
|
||||
var result = await mediator.SendOrThrowAsync(request, () => new InvalidOperationException("should not throw"));
|
||||
|
||||
Assert.That(result, Is.EqualTo(""));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SendOrNotFoundAsync — non-null scalar
|
||||
|
||||
[Test]
|
||||
public async Task SendOrNotFoundAsync_WithNonNullResponse_ReturnsResponse()
|
||||
{
|
||||
var mediator = CreateMediator<string>("hello");
|
||||
var request = new StubRequest<string?>();
|
||||
|
||||
var result = await mediator.SendOrNotFoundAsync(request);
|
||||
|
||||
Assert.That(result, Is.EqualTo("hello"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task SendOrNotFoundAsync_WithExceptionMessage_AndNonNullResponse_ReturnsResponse()
|
||||
{
|
||||
var mediator = CreateMediator<int>(42);
|
||||
var request = new StubRequest<int?>();
|
||||
|
||||
var result = await mediator.SendOrNotFoundAsync(request, "not found", CancellationToken.None);
|
||||
|
||||
Assert.That(result, Is.EqualTo(42));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SendOrNotFoundAsync — null response
|
||||
|
||||
[Test]
|
||||
public void SendOrNotFoundAsync_WithNullResponse_ThrowsNotFoundException()
|
||||
{
|
||||
var mediator = CreateMediator<string>(null);
|
||||
var request = new StubRequest<string?>();
|
||||
|
||||
Assert.ThrowsAsync<NotFoundException>(() => mediator.SendOrNotFoundAsync(request));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendOrNotFoundAsync_WithNullResponse_AndCustomMessage_ThrowsNotFoundExceptionWithMessage()
|
||||
{
|
||||
const string message = "Entity not found";
|
||||
var mediator = CreateMediator<string>(null);
|
||||
var request = new StubRequest<string?>();
|
||||
|
||||
var ex = Assert.ThrowsAsync<NotFoundException>(
|
||||
() => mediator.SendOrNotFoundAsync(request, message, CancellationToken.None));
|
||||
|
||||
Assert.That(ex!.Message, Does.Contain(message));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendOrNotFoundAsync_WithNullResponse_HasDefaultMessage()
|
||||
{
|
||||
var mediator = CreateMediator<string>(null);
|
||||
var request = new StubRequest<string?>();
|
||||
|
||||
var ex = Assert.ThrowsAsync<NotFoundException>(() => mediator.SendOrNotFoundAsync(request));
|
||||
|
||||
Assert.That(ex!.Message, Does.Contain(nameof(String)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SendOrNotFoundAsync — empty collection
|
||||
|
||||
[Test]
|
||||
public void SendOrNotFoundAsync_WithEmptyList_ThrowsNotFoundException()
|
||||
{
|
||||
var mediator = CreateMediator<List<string>>(new List<string>());
|
||||
var request = new StubRequest<List<string>?>();
|
||||
|
||||
Assert.ThrowsAsync<NotFoundException>(() => mediator.SendOrNotFoundAsync(request));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendOrNotFoundAsync_WithEmptyArray_ThrowsNotFoundException()
|
||||
{
|
||||
var mediator = CreateMediator<int[]>(Array.Empty<int>());
|
||||
var request = new StubRequest<int[]?>();
|
||||
|
||||
Assert.ThrowsAsync<NotFoundException>(() => mediator.SendOrNotFoundAsync(request));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendOrNotFoundAsync_WithEmptyCollection_AndCustomMessage_ThrowsNotFoundExceptionWithMessage()
|
||||
{
|
||||
const string message = "No items found";
|
||||
var mediator = CreateMediator<List<int>>(new List<int>());
|
||||
var request = new StubRequest<List<int>?>();
|
||||
|
||||
var ex = Assert.ThrowsAsync<NotFoundException>(
|
||||
() => mediator.SendOrNotFoundAsync(request, message, CancellationToken.None));
|
||||
|
||||
Assert.That(ex!.Message, Does.Contain(message));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SendOrNotFoundAsync — non-empty collection
|
||||
|
||||
[Test]
|
||||
public async Task SendOrNotFoundAsync_WithNonEmptyList_ReturnsResponse()
|
||||
{
|
||||
var expected = new List<string> { "a", "b" };
|
||||
var mediator = CreateMediator<List<string>>(expected);
|
||||
var request = new StubRequest<List<string>?>();
|
||||
|
||||
var result = await mediator.SendOrNotFoundAsync(request);
|
||||
|
||||
Assert.That(result, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task SendOrNotFoundAsync_WithNonEmptyArray_ReturnsResponse()
|
||||
{
|
||||
var expected = new[] { 1, 2, 3 };
|
||||
var mediator = CreateMediator<int[]>(expected);
|
||||
var request = new StubRequest<int[]?>();
|
||||
|
||||
var result = await mediator.SendOrNotFoundAsync(request);
|
||||
|
||||
Assert.That(result, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region CancellationToken
|
||||
|
||||
[Test]
|
||||
public void SendOrThrowAsync_WithCancelledToken_ThrowsOperationCanceledException()
|
||||
{
|
||||
var mediator = CreateMediator<string>("value");
|
||||
var request = new StubRequest<string?>();
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.Cancel();
|
||||
|
||||
Assert.ThrowsAsync<OperationCanceledException>(
|
||||
() => mediator.SendOrThrowAsync(request, () => new InvalidOperationException(), cts.Token));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendOrNotFoundAsync_WithCancelledToken_ThrowsOperationCanceledException()
|
||||
{
|
||||
var mediator = CreateMediator<string>("value");
|
||||
var request = new StubRequest<string?>();
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.Cancel();
|
||||
|
||||
Assert.ThrowsAsync<OperationCanceledException>(
|
||||
() => mediator.SendOrNotFoundAsync(request, cts.Token));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user