work-flow/tests/Workflow.Tests/StateMachine/TaskStateMachineTests.cs
2026-05-17 22:46:19 +08:00

358 lines
10 KiB
C#

using FluentAssertions;
using Workflow.Domain.Enums;
using Workflow.Domain.Exceptions;
using Workflow.Domain.StateMachine;
using Xunit;
using TaskStatus = Workflow.Domain.Enums.TaskStatus;
namespace Workflow.Tests.StateMachine;
/// <summary>
/// TaskStateMachine TDD 红灯阶段测试
/// 测试任务状态机的所有合法转换与非法转换
///
/// 任务状态: Pending, Approved, Rejected, Transferred, Delegated
/// 操作: Approve, Reject, Transfer, Delegate, DelegateComplete, TimeoutAutoProcess
/// </summary>
public class TaskStateMachineTests
{
private readonly TaskStateMachine _machine = new();
#region Pending Approved
[Fact]
public void Transition_Pending_To_Approved()
{
// Arrange - 正常审批通过
var currentState = TaskStatus.Pending;
var operation = TaskOperation.Approve;
var context = new TaskTransitionContext();
// Act
var newState = _machine.Transition(currentState, operation, context);
// Assert
newState.Should().Be(TaskStatus.Approved);
}
#endregion
#region Pending Rejected
[Fact]
public void Transition_Pending_To_Rejected()
{
// Arrange - 正常审批驳回
var currentState = TaskStatus.Pending;
var operation = TaskOperation.Reject;
var context = new TaskTransitionContext();
// Act
var newState = _machine.Transition(currentState, operation, context);
// Assert
newState.Should().Be(TaskStatus.Rejected);
}
#endregion
#region Pending Transferred
[Fact]
public void Transition_Pending_To_Transferred()
{
// Arrange - 转办:关闭原任务,为目标人创建新任务
var currentState = TaskStatus.Pending;
var operation = TaskOperation.Transfer;
var context = new TaskTransitionContext();
// Act
var newState = _machine.Transition(currentState, operation, context);
// Assert
newState.Should().Be(TaskStatus.Transferred);
}
#endregion
#region Pending Delegated
[Fact]
public void Transition_Pending_To_Delegated()
{
// Arrange - 委派:临时分配给他人处理,完成后归还
var currentState = TaskStatus.Pending;
var operation = TaskOperation.Delegate;
var context = new TaskTransitionContext();
// Act
var newState = _machine.Transition(currentState, operation, context);
// Assert
newState.Should().Be(TaskStatus.Delegated);
}
#endregion
#region Delegated Pending
[Fact]
public void Transition_Delegated_To_Pending_On_DelegateComplete()
{
// Arrange - 被委派人处理完毕,任务归还给委派人
var currentState = TaskStatus.Delegated;
var operation = TaskOperation.DelegateComplete;
var context = new TaskTransitionContext();
// Act
var newState = _machine.Transition(currentState, operation, context);
// Assert
newState.Should().Be(TaskStatus.Pending);
}
#endregion
#region Pending Approved/Rejected (Timeout Auto Process)
[Fact]
public void Transition_Pending_To_Approved_On_Timeout_With_AutoApprove_Config()
{
// Arrange - 超时自动审批通过(配置为自动通过)
var currentState = TaskStatus.Pending;
var operation = TaskOperation.TimeoutAutoProcess;
var context = new TaskTransitionContext
{
AutoApproveOnTimeout = true,
};
// Act
var newState = _machine.Transition(currentState, operation, context);
// Assert
newState.Should().Be(TaskStatus.Approved);
}
[Fact]
public void Transition_Pending_To_Rejected_On_Timeout_With_AutoReject_Config()
{
// Arrange - 超时自动审批驳回(配置为自动驳回)
var currentState = TaskStatus.Pending;
var operation = TaskOperation.TimeoutAutoProcess;
var context = new TaskTransitionContext
{
AutoApproveOnTimeout = false,
};
// Act
var newState = _machine.Transition(currentState, operation, context);
// Assert
newState.Should().Be(TaskStatus.Rejected);
}
#endregion
#region Illegal Transitions - Terminal States Cannot Transition
[Fact]
public void Transition_Approved_To_Pending_Should_Throw()
{
// Arrange - 已通过的任务不能回到待处理
var currentState = TaskStatus.Approved;
var operation = TaskOperation.Reject;
var context = new TaskTransitionContext();
// Act
var act = () => _machine.Transition(currentState, operation, context);
// Assert
act.Should().Throw<InvalidStateTransitionException>();
}
[Fact]
public void Transition_Rejected_To_Approved_Should_Throw()
{
// Arrange - 已驳回的任务不能变为通过
var currentState = TaskStatus.Rejected;
var operation = TaskOperation.Approve;
var context = new TaskTransitionContext();
// Act
var act = () => _machine.Transition(currentState, operation, context);
// Assert
act.Should().Throw<InvalidStateTransitionException>();
}
[Fact]
public void Transition_Transferred_To_Approved_Should_Throw()
{
// Arrange - 已转办的任务不能再审批
var currentState = TaskStatus.Transferred;
var operation = TaskOperation.Approve;
var context = new TaskTransitionContext();
// Act
var act = () => _machine.Transition(currentState, operation, context);
// Assert
act.Should().Throw<InvalidStateTransitionException>();
}
[Fact]
public void Transition_Transferred_To_Rejected_Should_Throw()
{
// Arrange - 已转办的任务不能再驳回
var currentState = TaskStatus.Transferred;
var operation = TaskOperation.Reject;
var context = new TaskTransitionContext();
// Act
var act = () => _machine.Transition(currentState, operation, context);
// Assert
act.Should().Throw<InvalidStateTransitionException>();
}
[Fact]
public void Transition_Approved_To_Approved_Should_Throw()
{
// Arrange - 已通过的任务不能再次通过
var currentState = TaskStatus.Approved;
var operation = TaskOperation.Approve;
var context = new TaskTransitionContext();
// Act
var act = () => _machine.Transition(currentState, operation, context);
// Assert
act.Should().Throw<InvalidStateTransitionException>();
}
[Fact]
public void Transition_Rejected_To_Rejected_Should_Throw()
{
// Arrange - 已驳回的任务不能再次驳回
var currentState = TaskStatus.Rejected;
var operation = TaskOperation.Reject;
var context = new TaskTransitionContext();
// Act
var act = () => _machine.Transition(currentState, operation, context);
// Assert
act.Should().Throw<InvalidStateTransitionException>();
}
#endregion
#region Illegal Transitions - DelegateComplete Only From Delegated
[Fact]
public void Transition_Pending_DelegateComplete_Should_Throw()
{
// Arrange - 非委派状态不能完成委派
var currentState = TaskStatus.Pending;
var operation = TaskOperation.DelegateComplete;
var context = new TaskTransitionContext();
// Act
var act = () => _machine.Transition(currentState, operation, context);
// Assert
act.Should().Throw<InvalidStateTransitionException>();
}
[Fact]
public void Transition_Approved_DelegateComplete_Should_Throw()
{
// Arrange - 已通过的任务不能完成委派
var currentState = TaskStatus.Approved;
var operation = TaskOperation.DelegateComplete;
var context = new TaskTransitionContext();
// Act
var act = () => _machine.Transition(currentState, operation, context);
// Assert
act.Should().Throw<InvalidStateTransitionException>();
}
#endregion
#region Illegal Transitions - Timeout Only From Pending
[Fact]
public void Transition_Delegated_TimeoutAutoProcess_Should_Throw()
{
// Arrange - 委派状态不支持超时自动处理
var currentState = TaskStatus.Delegated;
var operation = TaskOperation.TimeoutAutoProcess;
var context = new TaskTransitionContext
{
AutoApproveOnTimeout = true,
};
// Act
var act = () => _machine.Transition(currentState, operation, context);
// Assert
act.Should().Throw<InvalidStateTransitionException>();
}
[Fact]
public void Transition_Approved_TimeoutAutoProcess_Should_Throw()
{
// Arrange - 已通过的任务不支持超时处理
var currentState = TaskStatus.Approved;
var operation = TaskOperation.TimeoutAutoProcess;
var context = new TaskTransitionContext
{
AutoApproveOnTimeout = true,
};
// Act
var act = () => _machine.Transition(currentState, operation, context);
// Assert
act.Should().Throw<InvalidStateTransitionException>();
}
#endregion
#region Illegal Transitions - Delegated State Restrictions
[Fact]
public void Transition_Delegated_To_Approved_Should_Throw()
{
// Arrange - 委派中的任务不能直接审批通过,需先归还
var currentState = TaskStatus.Delegated;
var operation = TaskOperation.Approve;
var context = new TaskTransitionContext();
// Act
var act = () => _machine.Transition(currentState, operation, context);
// Assert
act.Should().Throw<InvalidStateTransitionException>();
}
[Fact]
public void Transition_Delegated_To_Rejected_Should_Throw()
{
// Arrange - 委派中的任务不能直接驳回,需先归还
var currentState = TaskStatus.Delegated;
var operation = TaskOperation.Reject;
var context = new TaskTransitionContext();
// Act
var act = () => _machine.Transition(currentState, operation, context);
// Assert
act.Should().Throw<InvalidStateTransitionException>();
}
#endregion
}