Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 59 additions & 47 deletions DannyGoodacre.Core.Tests/CommandQuery/CommandHandlerTests.cs
Original file line number Diff line number Diff line change
@@ -1,101 +1,116 @@
using DannyGoodacre.Core.CommandQuery;
using DannyGoodacre.Core.CommandQuery.Abstractions;
using Microsoft.Extensions.Logging;
using Moq;

namespace DannyGoodacre.Core.Tests.CommandQuery;

[TestFixture]
public class CommandHandlerTests : TestBase
{
public class TestCommand : ICommand;
public class TestCommandRequest : ICommandRequest;

private const string TestName = "Test Command Handler";
public class TestCommandHandler(ILogger logger) : CommandHandler<TestCommandRequest>(logger)
{
protected override string CommandName => TestName;

protected override void Validate(ValidationState validationState, TestCommandRequest commandRequest)
=> _testValidate(validationState, commandRequest);

private const string TestProperty = "Test Property";
protected override Task<Result> InternalExecuteAsync(TestCommandRequest commandRequest, CancellationToken cancellationToken)
=> _testInternalExecuteAsync(commandRequest, cancellationToken);

private const string TestError = "Test Error";
public Task<Result> TestExecuteAsync(TestCommandRequest commandRequest, CancellationToken cancellationToken)
=> ExecuteAsync(commandRequest, cancellationToken);
}

private const string TestExceptionMessage = "Test Exception Message";
private const string TestName = "Test Command Handler";

private readonly CancellationToken _testCancellationToken = CancellationToken.None;
private CancellationToken _testCancellationToken;

private readonly TestCommand _testCommand = new();
private Mock<ILogger<TestCommandHandler>> _loggerMock = null!;

private static Action<ValidationState, TestCommand> _validate = (_, _) => {};
private static Action<ValidationState, TestCommandRequest> _testValidate = null!;

private static Func<TestCommand, CancellationToken, Task<Result>> _internalExecuteAsync = (_, _) => Task.FromResult(new Result());
private static Func<TestCommandRequest, CancellationToken, Task<Result>> _testInternalExecuteAsync = null!;

private Mock<ILogger<TestCommandHandler>> _loggerMock = null!;
private static TestCommandRequest _testCommandRequest = null!;

public class TestCommandHandler(ILogger logger) : CommandHandler<TestCommand>(logger)
private static TestCommandHandler _testCommandHandler = null!;

[SetUp]
public void SetUp()
{
protected override string CommandName => TestName;
_testCancellationToken = CancellationToken.None;

protected override void Validate(ValidationState validationState, TestCommand command)
=> _validate(validationState, command);
_testValidate = (_, _) => {};

protected override Task<Result> InternalExecuteAsync(TestCommand command, CancellationToken cancellationToken)
=> _internalExecuteAsync(command, cancellationToken);
_testInternalExecuteAsync = (_, _) => Task.FromResult(Result.Success());

_loggerMock = new Mock<ILogger<TestCommandHandler>>(MockBehavior.Strict);

public Task<Result> TestExecuteAsync(TestCommand command, CancellationToken cancellationToken)
=> ExecuteAsync(command, cancellationToken);
_testCommandRequest = new TestCommandRequest();

_testCommandHandler = new TestCommandHandler(_loggerMock.Object);
}

[Test]
public async Task ExecuteAsync_WhenValidationFails_ShouldReturnInvalid()
{
// Arrange
_loggerMock = new Mock<ILogger<TestCommandHandler>>(MockBehavior.Strict);
const string testProperty = "Test Property";

_loggerMock.Setup(LogLevel.Error, $"Command '{TestName}' failed validation: {TestProperty}:{Environment.NewLine} - {TestError}");
const string testError = "Test Error";

_validate = (validationState, _)
=> validationState.AddError(TestProperty, TestError);
_loggerMock.Setup(LogLevel.Error, $"Command '{TestName}' failed validation: {testProperty}:{Environment.NewLine} - {testError}");

var handler = new TestCommandHandler(_loggerMock.Object);
_testValidate = (validationState, _) => validationState.AddError(testProperty, testError);

// Act
var result = await handler.TestExecuteAsync(_testCommand, _testCancellationToken);
var result = await Act();

// Assert
AssertInvalid(result);
}

[Test]
public async Task ExecuteAsync_WhenCancelled_ShouldReturnCancelled()
public async Task ExecuteAsync_WhenCancelledBefore_ShouldReturnCancelled()
{
// Arrange
var cancellationTokenSource = new CancellationTokenSource();

_loggerMock = new Mock<ILogger<TestCommandHandler>>(MockBehavior.Strict);
_testCancellationToken = cancellationTokenSource.Token;

_loggerMock.Setup(LogLevel.Information, $"Command '{TestName}' was cancelled before execution.");

var handler = new TestCommandHandler(_loggerMock.Object);

await cancellationTokenSource.CancelAsync();

// Act
var result = await handler.TestExecuteAsync(_testCommand, cancellationTokenSource.Token);
var result = await Act();

// Assert
AssertCancelled(result);
}

[Test]
public async Task ExecuteAsync_WhenSuccessful_ShouldReturnSuccess()
{
// Act
var result = await Act();

// Assert
AssertSuccess(result);
}

[Test]
public async Task ExecuteAsync_WhenCancelledDuring_ShouldReturnCancelled()
{
// Arrange
_loggerMock = new Mock<ILogger<TestCommandHandler>>(MockBehavior.Strict);

_loggerMock.Setup(LogLevel.Information, $"Command '{TestName}' was cancelled during execution.");

_internalExecuteAsync = (_, _) => throw new OperationCanceledException();

var handler = new TestCommandHandler(_loggerMock.Object);
_testInternalExecuteAsync = (_, _) => throw new OperationCanceledException();

// Act
var result = await handler.TestExecuteAsync(_testCommand, _testCancellationToken);
var result = await Act();

// Assert
AssertCancelled(result);
Expand All @@ -105,23 +120,20 @@ public async Task ExecuteAsync_WhenCancelledDuring_ShouldReturnCancelled()
public async Task ExecuteAsync_WhenExceptionOccurs_ShouldReturnInternalError()
{
// Arrange
var exception = new ApplicationException(TestExceptionMessage);
const string testExceptionMessage = "Test Exception Message";

_loggerMock = new Mock<ILogger<TestCommandHandler>>(MockBehavior.Strict);

_loggerMock.Setup(
LogLevel.Critical,
$"Command '{TestName}' failed with exception: {TestExceptionMessage}",
exception: exception);
var exception = new Exception(testExceptionMessage);

_internalExecuteAsync = (_, _) => throw exception;
_loggerMock.Setup(LogLevel.Critical, $"Command '{TestName}' failed with exception: {testExceptionMessage}", exception: exception);

var handler = new TestCommandHandler(_loggerMock.Object);
_testInternalExecuteAsync = (_, _) => throw exception;

// Act
var result = await handler.TestExecuteAsync(_testCommand, _testCancellationToken);
var result = await Act();

// Assert
AssertInternalError(result, TestExceptionMessage);
AssertInternalError(result, testExceptionMessage);
}

private Task<Result> Act() => _testCommandHandler.TestExecuteAsync(_testCommandRequest, _testCancellationToken);
}
109 changes: 63 additions & 46 deletions DannyGoodacre.Core.Tests/CommandQuery/CommandHandlerValueTests.cs
Original file line number Diff line number Diff line change
@@ -1,100 +1,120 @@
using DannyGoodacre.Core.CommandQuery;
using DannyGoodacre.Core.CommandQuery.Abstractions;
using Microsoft.Extensions.Logging;
using Moq;

namespace DannyGoodacre.Core.Tests.CommandQuery;

[TestFixture]
public class CommandHandlerValueTests : TestBase
{
public class TestCommand : ICommand;
public class TestCommandRequest : ICommandRequest;

private const string TestName = "Test Command Handler";

private const string TestProperty = "Test Property";
public class TestCommandHandler(ILogger logger) : CommandHandler<TestCommandRequest, int>(logger)
{
protected override string CommandName => TestName;

private const string TestError = "Test Error";
protected override void Validate(ValidationState validationState, TestCommandRequest commandRequest)
=> _testValidate(validationState, commandRequest);

private const string TestExceptionMessage = "Test Exception Message";
protected override Task<Result<int>> InternalExecuteAsync(TestCommandRequest commandRequest, CancellationToken cancellationToken)
=> _testInternalExecuteAsync(commandRequest, cancellationToken);

private readonly CancellationToken _testCancellationToken = CancellationToken.None;
public Task<Result<int>> TestExecuteAsync(TestCommandRequest commandRequest, CancellationToken cancellationToken)
=> ExecuteAsync(commandRequest, cancellationToken);
}

private readonly TestCommand _testCommand = new();
private const string TestName = "Test Command Handler";

private static Action<ValidationState, TestCommand> _validate = (_, _) => {};
private int _testResultValue;

private static Func<TestCommand, CancellationToken, Task<Result<string>>> _internalExecuteAsync = (_, _) => Task.FromResult(Result<string>.Success("Test result value"));
private CancellationToken _testCancellationToken;

private Mock<ILogger<TestCommandHandler>> _loggerMock = null!;

public class TestCommandHandler(ILogger logger) : CommandHandler<TestCommand, string>(logger)
private static Action<ValidationState, TestCommandRequest> _testValidate = null!;

private static Func<TestCommandRequest, CancellationToken, Task<Result<int>>> _testInternalExecuteAsync = null!;

private static TestCommandRequest _testCommandRequest = null!;

private static TestCommandHandler _testCommandHandler = null!;

[SetUp]
public void SetUp()
{
protected override string CommandName => TestName;
_testResultValue = 123;

_testCancellationToken = CancellationToken.None;

protected override void Validate(ValidationState validationState, TestCommand command)
=> _validate(validationState, command);
_testValidate = (_, _) => {};

protected override Task<Result<string>> InternalExecuteAsync(TestCommand command, CancellationToken cancellationToken)
=> _internalExecuteAsync(command, cancellationToken);
_testInternalExecuteAsync = (_, _) => Task.FromResult(Result<int>.Success(_testResultValue));

public Task<Result<string>> TestExecuteAsync(TestCommand command, CancellationToken cancellationToken) => ExecuteAsync(command, cancellationToken);
_loggerMock = new Mock<ILogger<TestCommandHandler>>(MockBehavior.Strict);

_testCommandRequest = new TestCommandRequest();

_testCommandHandler = new TestCommandHandler(_loggerMock.Object);
}

[Test]
public async Task ExecuteAsync_WhenValidationFails_ShouldReturnInvalid()
{
// Arrange
_loggerMock = new Mock<ILogger<TestCommandHandler>>(MockBehavior.Strict);
const string testProperty = "Test Property";

_loggerMock.Setup(LogLevel.Error, $"Command '{TestName}' failed validation: {TestProperty}:{Environment.NewLine} - {TestError}");
const string testError = "Test Error";

_validate = (validationState, _)
=> validationState.AddError(TestProperty, TestError);
_loggerMock.Setup(LogLevel.Error, $"Command '{TestName}' failed validation: {testProperty}:{Environment.NewLine} - {testError}");

var handler = new TestCommandHandler(_loggerMock.Object);
_testValidate = (validationState, _) => validationState.AddError(testProperty, testError);

// Act
var result = await handler.TestExecuteAsync(_testCommand, _testCancellationToken);
var result = await Act();

// Assert
AssertInvalid(result);
}

[Test]
public async Task ExecuteAsync_WhenCancelled_ShouldReturnCancelled()
public async Task ExecuteAsync_WhenCancelledBefore_ShouldReturnCancelled()
{
// Arrange
var cancellationTokenSource = new CancellationTokenSource();

_loggerMock = new Mock<ILogger<TestCommandHandler>>(MockBehavior.Strict);
_testCancellationToken = cancellationTokenSource.Token;

_loggerMock.Setup(LogLevel.Information, $"Command '{TestName}' was cancelled before execution.");

var handler = new TestCommandHandler(_loggerMock.Object);

await cancellationTokenSource.CancelAsync();

// Act
var result = await handler.TestExecuteAsync(_testCommand, cancellationTokenSource.Token);
var result = await Act();

// Assert
AssertCancelled(result);
}

[Test]
public async Task ExecuteAsync_WhenSuccessful_ShouldReturnSuccess()
{
// Act
var result = await Act();

// Assert
AssertSuccess(result, _testResultValue);
}

[Test]
public async Task ExecuteAsync_WhenCancelledDuring_ShouldReturnCancelled()
{
// Arrange
_loggerMock = new Mock<ILogger<TestCommandHandler>>(MockBehavior.Strict);

_loggerMock.Setup(LogLevel.Information, $"Command '{TestName}' was cancelled during execution.");

_internalExecuteAsync = (_, _) => throw new OperationCanceledException();

var handler = new TestCommandHandler(_loggerMock.Object);
_testInternalExecuteAsync = (_, _) => throw new OperationCanceledException();

// Act
var result = await handler.TestExecuteAsync(_testCommand, _testCancellationToken);
var result = await Act();

// Assert
AssertCancelled(result);
Expand All @@ -104,23 +124,20 @@ public async Task ExecuteAsync_WhenCancelledDuring_ShouldReturnCancelled()
public async Task ExecuteAsync_WhenExceptionOccurs_ShouldReturnInternalError()
{
// Arrange
var exception = new ApplicationException(TestExceptionMessage);
const string testExceptionMessage = "Test Exception Message";

_loggerMock = new Mock<ILogger<TestCommandHandler>>(MockBehavior.Strict);

_loggerMock.Setup(
LogLevel.Critical,
$"Command '{TestName}' failed with exception: {TestExceptionMessage}",
exception: exception);
var exception = new Exception(testExceptionMessage);

_internalExecuteAsync = (_, _) => throw exception;
_loggerMock.Setup(LogLevel.Critical, $"Command '{TestName}' failed with exception: {testExceptionMessage}", exception: exception);

var handler = new TestCommandHandler(_loggerMock.Object);
_testInternalExecuteAsync = (_, _) => throw exception;

// Act
var result = await handler.TestExecuteAsync(_testCommand, _testCancellationToken);
var result = await Act();

// Assert
AssertInternalError(result, TestExceptionMessage);
AssertInternalError(result, testExceptionMessage);
}

private Task<Result<int>> Act() => _testCommandHandler.TestExecuteAsync(_testCommandRequest, _testCancellationToken);
}
Loading