Renamed SendOrThrowAsync and SendOrNotFoundAsync extension methods for IMediator to GetOrThrow for ISender, following MediatR best practices. Updated all usages, XML docs, and tests to use ISender and the new method names. Replaced StubMediator with StubSender in tests. Functionality remains the same, but code now aligns with modern MediatR conventions.
282 lines
8.8 KiB
C#
282 lines
8.8 KiB
C#
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="ISender"/> stub that returns a pre-configured response for any <see cref="ISender.Send{TResponse}"/> call.
|
|
/// </summary>
|
|
private sealed class StubSender : ISender
|
|
{
|
|
private readonly object? _response;
|
|
|
|
public StubSender(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();
|
|
}
|
|
|
|
private static ISender CreateSender<T>(T? response) => new StubSender(response);
|
|
|
|
#endregion
|
|
|
|
#region GetOrThrow<TResponse, TException> — non-null scalar
|
|
|
|
[Test]
|
|
public async Task GetOrThrow_WithNonNullResponse_ReturnsResponse()
|
|
{
|
|
var sender = CreateSender<string>("hello");
|
|
var request = new StubRequest<string?>();
|
|
|
|
var result = await sender.GetOrThrow(request, () => new InvalidOperationException());
|
|
|
|
Assert.That(result, Is.EqualTo("hello"));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetOrThrow<TResponse, TException> — null response
|
|
|
|
[Test]
|
|
public void GetOrThrow_WithNullResponse_ThrowsCustomException()
|
|
{
|
|
var sender = CreateSender<string>(null);
|
|
var request = new StubRequest<string?>();
|
|
|
|
var ex = Assert.ThrowsAsync<InvalidOperationException>(
|
|
() => sender.GetOrThrow(request, () => new InvalidOperationException("custom")));
|
|
|
|
Assert.That(ex!.Message, Is.EqualTo("custom"));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetOrThrow<TResponse, TException> — empty collection
|
|
|
|
[Test]
|
|
public void GetOrThrow_WithEmptyList_ThrowsCustomException()
|
|
{
|
|
var sender = CreateSender<List<string>>(new List<string>());
|
|
var request = new StubRequest<List<string>?>();
|
|
|
|
Assert.ThrowsAsync<ArgumentException>(
|
|
() => sender.GetOrThrow(request, () => new ArgumentException("empty")));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetOrThrow<TResponse, TException> — non-empty collection
|
|
|
|
[Test]
|
|
public async Task GetOrThrow_WithNonEmptyList_ReturnsResponse()
|
|
{
|
|
var expected = new List<int> { 1, 2 };
|
|
var sender = CreateSender<List<int>>(expected);
|
|
var request = new StubRequest<List<int>?>();
|
|
|
|
var result = await sender.GetOrThrow(request, () => new InvalidOperationException());
|
|
|
|
Assert.That(result, Is.EqualTo(expected));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetOrThrow<TResponse, TException> — string edge case (string implements IEnumerable)
|
|
|
|
[Test]
|
|
public async Task GetOrThrow_WithEmptyString_ReturnsEmptyString()
|
|
{
|
|
var sender = CreateSender<string>("");
|
|
var request = new StubRequest<string?>();
|
|
|
|
var result = await sender.GetOrThrow(request, () => new InvalidOperationException("should not throw"));
|
|
|
|
Assert.That(result, Is.EqualTo(""));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetOrThrow<TResponse> (NotFoundException) — non-null scalar
|
|
|
|
[Test]
|
|
public async Task GetOrThrow_NotFound_WithNonNullResponse_ReturnsResponse()
|
|
{
|
|
var sender = CreateSender<string>("hello");
|
|
var request = new StubRequest<string?>();
|
|
|
|
var result = await sender.GetOrThrow(request);
|
|
|
|
Assert.That(result, Is.EqualTo("hello"));
|
|
}
|
|
|
|
[Test]
|
|
public async Task GetOrThrow_NotFound_WithExceptionMessage_AndNonNullResponse_ReturnsResponse()
|
|
{
|
|
var sender = CreateSender<int>(42);
|
|
var request = new StubRequest<int?>();
|
|
|
|
var result = await sender.GetOrThrow(request, "not found", CancellationToken.None);
|
|
|
|
Assert.That(result, Is.EqualTo(42));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetOrThrow<TResponse> (NotFoundException) — null response
|
|
|
|
[Test]
|
|
public void GetOrThrow_NotFound_WithNullResponse_ThrowsNotFoundException()
|
|
{
|
|
var sender = CreateSender<string>(null);
|
|
var request = new StubRequest<string?>();
|
|
|
|
Assert.ThrowsAsync<NotFoundException>(() => sender.GetOrThrow(request));
|
|
}
|
|
|
|
[Test]
|
|
public void GetOrThrow_NotFound_WithNullResponse_AndCustomMessage_ContainsMessage()
|
|
{
|
|
const string message = "Entity not found";
|
|
var sender = CreateSender<string>(null);
|
|
var request = new StubRequest<string?>();
|
|
|
|
var ex = Assert.ThrowsAsync<NotFoundException>(
|
|
() => sender.GetOrThrow(request, message, CancellationToken.None));
|
|
|
|
Assert.That(ex!.Message, Does.Contain(message));
|
|
}
|
|
|
|
[Test]
|
|
public void GetOrThrow_NotFound_WithNullResponse_HasDefaultMessageWithTypeName()
|
|
{
|
|
var sender = CreateSender<string>(null);
|
|
var request = new StubRequest<string?>();
|
|
|
|
var ex = Assert.ThrowsAsync<NotFoundException>(() => sender.GetOrThrow(request));
|
|
|
|
Assert.That(ex!.Message, Does.Contain(nameof(String)));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetOrThrow<TResponse> (NotFoundException) — empty collection
|
|
|
|
[Test]
|
|
public void GetOrThrow_NotFound_WithEmptyList_ThrowsNotFoundException()
|
|
{
|
|
var sender = CreateSender<List<string>>(new List<string>());
|
|
var request = new StubRequest<List<string>?>();
|
|
|
|
Assert.ThrowsAsync<NotFoundException>(() => sender.GetOrThrow(request));
|
|
}
|
|
|
|
[Test]
|
|
public void GetOrThrow_NotFound_WithEmptyArray_ThrowsNotFoundException()
|
|
{
|
|
var sender = CreateSender<int[]>(Array.Empty<int>());
|
|
var request = new StubRequest<int[]?>();
|
|
|
|
Assert.ThrowsAsync<NotFoundException>(() => sender.GetOrThrow(request));
|
|
}
|
|
|
|
[Test]
|
|
public void GetOrThrow_NotFound_WithEmptyCollection_AndCustomMessage_ContainsMessage()
|
|
{
|
|
const string message = "No items found";
|
|
var sender = CreateSender<List<int>>(new List<int>());
|
|
var request = new StubRequest<List<int>?>();
|
|
|
|
var ex = Assert.ThrowsAsync<NotFoundException>(
|
|
() => sender.GetOrThrow(request, message, CancellationToken.None));
|
|
|
|
Assert.That(ex!.Message, Does.Contain(message));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetOrThrow<TResponse> (NotFoundException) — non-empty collection
|
|
|
|
[Test]
|
|
public async Task GetOrThrow_NotFound_WithNonEmptyList_ReturnsResponse()
|
|
{
|
|
var expected = new List<string> { "a", "b" };
|
|
var sender = CreateSender<List<string>>(expected);
|
|
var request = new StubRequest<List<string>?>();
|
|
|
|
var result = await sender.GetOrThrow(request);
|
|
|
|
Assert.That(result, Is.EqualTo(expected));
|
|
}
|
|
|
|
[Test]
|
|
public async Task GetOrThrow_NotFound_WithNonEmptyArray_ReturnsResponse()
|
|
{
|
|
var expected = new[] { 1, 2, 3 };
|
|
var sender = CreateSender<int[]>(expected);
|
|
var request = new StubRequest<int[]?>();
|
|
|
|
var result = await sender.GetOrThrow(request);
|
|
|
|
Assert.That(result, Is.EqualTo(expected));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CancellationToken
|
|
|
|
[Test]
|
|
public void GetOrThrow_WithCancelledToken_ThrowsOperationCanceledException()
|
|
{
|
|
var sender = CreateSender<string>("value");
|
|
var request = new StubRequest<string?>();
|
|
var cts = new CancellationTokenSource();
|
|
cts.Cancel();
|
|
|
|
Assert.ThrowsAsync<OperationCanceledException>(
|
|
() => sender.GetOrThrow(request, () => new InvalidOperationException(), cts.Token));
|
|
}
|
|
|
|
[Test]
|
|
public void GetOrThrow_NotFound_WithCancelledToken_ThrowsOperationCanceledException()
|
|
{
|
|
var sender = CreateSender<string>("value");
|
|
var request = new StubRequest<string?>();
|
|
var cts = new CancellationTokenSource();
|
|
cts.Cancel();
|
|
|
|
Assert.ThrowsAsync<OperationCanceledException>(
|
|
() => sender.GetOrThrow(request, cts.Token));
|
|
}
|
|
|
|
#endregion
|
|
}
|