Refactor MediatorExtensions to fluent GetOr/Throw API
Replaced GetOrThrow methods with a fluent GetOr/Throw pattern for handling null or empty MediatR responses. Introduced GetOrContext<TResponse> struct with Throw, ThrowNotFound, ThrowInvalidOperation, and ThrowBadRequest methods. Updated all tests to use the new API and added coverage for new exception types. Improved XML docs and performed minor code cleanup.
This commit is contained in:
@@ -49,212 +49,239 @@ public class MediatorExtensionsTests
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetOrThrow<TResponse, TException> — non-null scalar
|
||||
#region Throw — non-null scalar
|
||||
|
||||
[Test]
|
||||
public async Task GetOrThrow_WithNonNullResponse_ReturnsResponse()
|
||||
public async Task Throw_WithNonNullResponse_ReturnsResponse()
|
||||
{
|
||||
var sender = CreateSender<string>("hello");
|
||||
var request = new StubRequest<string?>();
|
||||
|
||||
var result = await sender.GetOrThrow(request, () => new InvalidOperationException());
|
||||
var result = await sender.GetOr(request).Throw(() => new InvalidOperationException());
|
||||
|
||||
Assert.That(result, Is.EqualTo("hello"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetOrThrow<TResponse, TException> — null response
|
||||
#region Throw — null response
|
||||
|
||||
[Test]
|
||||
public void GetOrThrow_WithNullResponse_ThrowsCustomException()
|
||||
public void Throw_WithNullResponse_ThrowsCustomException()
|
||||
{
|
||||
var sender = CreateSender<string>(null);
|
||||
var request = new StubRequest<string?>();
|
||||
|
||||
var ex = Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => sender.GetOrThrow(request, () => new InvalidOperationException("custom")));
|
||||
() => sender.GetOr(request).Throw(() => new InvalidOperationException("custom")));
|
||||
|
||||
Assert.That(ex!.Message, Is.EqualTo("custom"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetOrThrow<TResponse, TException> — empty collection
|
||||
#region Throw — empty collection
|
||||
|
||||
[Test]
|
||||
public void GetOrThrow_WithEmptyList_ThrowsCustomException()
|
||||
public void Throw_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")));
|
||||
() => sender.GetOr(request).Throw(() => new ArgumentException("empty")));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetOrThrow<TResponse, TException> — non-empty collection
|
||||
#region Throw — non-empty collection
|
||||
|
||||
[Test]
|
||||
public async Task GetOrThrow_WithNonEmptyList_ReturnsResponse()
|
||||
public async Task Throw_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());
|
||||
var result = await sender.GetOr(request).Throw(() => new InvalidOperationException());
|
||||
|
||||
Assert.That(result, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetOrThrow<TResponse, TException> — string edge case (string implements IEnumerable)
|
||||
#region Throw — string edge case (string implements IEnumerable)
|
||||
|
||||
[Test]
|
||||
public async Task GetOrThrow_WithEmptyString_ReturnsEmptyString()
|
||||
public async Task Throw_WithEmptyString_ReturnsEmptyString()
|
||||
{
|
||||
var sender = CreateSender<string>("");
|
||||
var request = new StubRequest<string?>();
|
||||
|
||||
var result = await sender.GetOrThrow(request, () => new InvalidOperationException("should not throw"));
|
||||
var result = await sender.GetOr(request).Throw(() => new InvalidOperationException("should not throw"));
|
||||
|
||||
Assert.That(result, Is.EqualTo(""));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetOrThrow<TResponse> (NotFoundException) — non-null scalar
|
||||
#region ThrowNotFound — non-null scalar
|
||||
|
||||
[Test]
|
||||
public async Task GetOrThrow_NotFound_WithNonNullResponse_ReturnsResponse()
|
||||
public async Task ThrowNotFound_WithNonNullResponse_ReturnsResponse()
|
||||
{
|
||||
var sender = CreateSender<string>("hello");
|
||||
var request = new StubRequest<string?>();
|
||||
|
||||
var result = await sender.GetOrThrow(request);
|
||||
var result = await sender.GetOr(request).ThrowNotFound();
|
||||
|
||||
Assert.That(result, Is.EqualTo("hello"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetOrThrow_NotFound_WithExceptionMessage_AndNonNullResponse_ReturnsResponse()
|
||||
public async Task ThrowNotFound_WithExceptionMessage_AndNonNullResponse_ReturnsResponse()
|
||||
{
|
||||
var sender = CreateSender<int>(42);
|
||||
var request = new StubRequest<int?>();
|
||||
|
||||
var result = await sender.GetOrThrow(request, "not found", CancellationToken.None);
|
||||
var result = await sender.GetOr(request).ThrowNotFound("not found");
|
||||
|
||||
Assert.That(result, Is.EqualTo(42));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetOrThrow<TResponse> (NotFoundException) — null response
|
||||
#region ThrowNotFound — null response
|
||||
|
||||
[Test]
|
||||
public void GetOrThrow_NotFound_WithNullResponse_ThrowsNotFoundException()
|
||||
public void ThrowNotFound_WithNullResponse_ThrowsNotFoundException()
|
||||
{
|
||||
var sender = CreateSender<string>(null);
|
||||
var request = new StubRequest<string?>();
|
||||
|
||||
Assert.ThrowsAsync<NotFoundException>(() => sender.GetOrThrow(request));
|
||||
Assert.ThrowsAsync<NotFoundException>(() => sender.GetOr(request).ThrowNotFound());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetOrThrow_NotFound_WithNullResponse_AndCustomMessage_ContainsMessage()
|
||||
public void ThrowNotFound_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));
|
||||
() => sender.GetOr(request).ThrowNotFound(message));
|
||||
|
||||
Assert.That(ex!.Message, Does.Contain(message));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetOrThrow_NotFound_WithNullResponse_HasDefaultMessageWithTypeName()
|
||||
public void ThrowNotFound_WithNullResponse_HasDefaultMessageWithTypeName()
|
||||
{
|
||||
var sender = CreateSender<string>(null);
|
||||
var request = new StubRequest<string?>();
|
||||
|
||||
var ex = Assert.ThrowsAsync<NotFoundException>(() => sender.GetOrThrow(request));
|
||||
var ex = Assert.ThrowsAsync<NotFoundException>(() => sender.GetOr(request).ThrowNotFound());
|
||||
|
||||
Assert.That(ex!.Message, Does.Contain(nameof(String)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetOrThrow<TResponse> (NotFoundException) — empty collection
|
||||
#region ThrowNotFound — empty collection
|
||||
|
||||
[Test]
|
||||
public void GetOrThrow_NotFound_WithEmptyList_ThrowsNotFoundException()
|
||||
public void ThrowNotFound_WithEmptyList_ThrowsNotFoundException()
|
||||
{
|
||||
var sender = CreateSender<List<string>>(new List<string>());
|
||||
var request = new StubRequest<List<string>?>();
|
||||
|
||||
Assert.ThrowsAsync<NotFoundException>(() => sender.GetOrThrow(request));
|
||||
Assert.ThrowsAsync<NotFoundException>(() => sender.GetOr(request).ThrowNotFound());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetOrThrow_NotFound_WithEmptyArray_ThrowsNotFoundException()
|
||||
public void ThrowNotFound_WithEmptyArray_ThrowsNotFoundException()
|
||||
{
|
||||
var sender = CreateSender<int[]>(Array.Empty<int>());
|
||||
var request = new StubRequest<int[]?>();
|
||||
|
||||
Assert.ThrowsAsync<NotFoundException>(() => sender.GetOrThrow(request));
|
||||
Assert.ThrowsAsync<NotFoundException>(() => sender.GetOr(request).ThrowNotFound());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetOrThrow_NotFound_WithEmptyCollection_AndCustomMessage_ContainsMessage()
|
||||
public void ThrowNotFound_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));
|
||||
() => sender.GetOr(request).ThrowNotFound(message));
|
||||
|
||||
Assert.That(ex!.Message, Does.Contain(message));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetOrThrow<TResponse> (NotFoundException) — non-empty collection
|
||||
#region ThrowNotFound — non-empty collection
|
||||
|
||||
[Test]
|
||||
public async Task GetOrThrow_NotFound_WithNonEmptyList_ReturnsResponse()
|
||||
public async Task ThrowNotFound_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);
|
||||
var result = await sender.GetOr(request).ThrowNotFound();
|
||||
|
||||
Assert.That(result, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetOrThrow_NotFound_WithNonEmptyArray_ReturnsResponse()
|
||||
public async Task ThrowNotFound_WithNonEmptyArray_ReturnsResponse()
|
||||
{
|
||||
var expected = new[] { 1, 2, 3 };
|
||||
var sender = CreateSender<int[]>(expected);
|
||||
var request = new StubRequest<int[]?>();
|
||||
|
||||
var result = await sender.GetOrThrow(request);
|
||||
var result = await sender.GetOr(request).ThrowNotFound();
|
||||
|
||||
Assert.That(result, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ThrowInvalidOperation — null response
|
||||
|
||||
[Test]
|
||||
public void ThrowInvalidOperation_WithNullResponse_ThrowsInvalidOperationException()
|
||||
{
|
||||
var sender = CreateSender<string>(null);
|
||||
var request = new StubRequest<string?>();
|
||||
|
||||
Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => sender.GetOr(request).ThrowInvalidOperation());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ThrowInvalidOperation_WithNullResponse_AndCustomMessage_ContainsMessage()
|
||||
{
|
||||
const string message = "Something went wrong";
|
||||
var sender = CreateSender<string>(null);
|
||||
var request = new StubRequest<string?>();
|
||||
|
||||
var ex = Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => sender.GetOr(request).ThrowInvalidOperation(message));
|
||||
|
||||
Assert.That(ex!.Message, Does.Contain(message));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region CancellationToken
|
||||
|
||||
[Test]
|
||||
public void GetOrThrow_WithCancelledToken_ThrowsOperationCanceledException()
|
||||
public void Throw_WithCancelledToken_ThrowsOperationCanceledException()
|
||||
{
|
||||
var sender = CreateSender<string>("value");
|
||||
var request = new StubRequest<string?>();
|
||||
@@ -262,11 +289,11 @@ public class MediatorExtensionsTests
|
||||
cts.Cancel();
|
||||
|
||||
Assert.ThrowsAsync<OperationCanceledException>(
|
||||
() => sender.GetOrThrow(request, () => new InvalidOperationException(), cts.Token));
|
||||
() => sender.GetOr(request, cts.Token).Throw(() => new InvalidOperationException()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetOrThrow_NotFound_WithCancelledToken_ThrowsOperationCanceledException()
|
||||
public void ThrowNotFound_WithCancelledToken_ThrowsOperationCanceledException()
|
||||
{
|
||||
var sender = CreateSender<string>("value");
|
||||
var request = new StubRequest<string?>();
|
||||
@@ -274,7 +301,7 @@ public class MediatorExtensionsTests
|
||||
cts.Cancel();
|
||||
|
||||
Assert.ThrowsAsync<OperationCanceledException>(
|
||||
() => sender.GetOrThrow(request, cts.Token));
|
||||
() => sender.GetOr(request, cts.Token).ThrowNotFound());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
Reference in New Issue
Block a user