358 lines
10 KiB
C#
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
|
|
}
|