265 lines
8.7 KiB
C#
265 lines
8.7 KiB
C#
using FsCheck;
|
||
using FsCheck.Xunit;
|
||
using Xunit;
|
||
using XiangYi.Application.Services;
|
||
using XiangYi.Core.Enums;
|
||
|
||
namespace XiangYi.Application.Tests.Services;
|
||
|
||
/// <summary>
|
||
/// AdminProfileAuditService属性测试
|
||
/// </summary>
|
||
public class AdminProfileAuditServicePropertyTests
|
||
{
|
||
/// <summary>
|
||
/// **Feature: backend-api, Property 24: 资料审核状态流转**
|
||
/// **Validates: Requirements 14.1, 14.3, 14.4, 14.5**
|
||
///
|
||
/// *For any* 用户资料, 状态应从"待审核"流转到"已通过"或"已拒绝",
|
||
/// 且只有"已通过"状态的资料才能在列表展示
|
||
///
|
||
/// 此测试验证:从待审核状态可以流转到已通过或已拒绝
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public Property StatusTransition_FromPending_ShouldAllowApproveOrReject()
|
||
{
|
||
// Generate target status (Approved or Rejected)
|
||
var targetStatusArb = Gen.Elements(
|
||
(int)AuditStatus.Approved,
|
||
(int)AuditStatus.Rejected);
|
||
|
||
return Prop.ForAll(
|
||
targetStatusArb.ToArbitrary(),
|
||
targetStatus =>
|
||
{
|
||
// Act
|
||
var isValid = AdminProfileAuditService.IsValidStatusTransitionStatic(
|
||
(int)AuditStatus.Pending,
|
||
targetStatus);
|
||
|
||
// Assert - From Pending, should allow transition to Approved or Rejected
|
||
return isValid;
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 状态流转 - 从待审核不能流转到待审核
|
||
/// </summary>
|
||
[Fact]
|
||
public void StatusTransition_FromPending_ToPending_ShouldBeInvalid()
|
||
{
|
||
var isValid = AdminProfileAuditService.IsValidStatusTransitionStatic(
|
||
(int)AuditStatus.Pending,
|
||
(int)AuditStatus.Pending);
|
||
|
||
Assert.False(isValid);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 状态流转 - 从已通过不能流转到任何状态
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public Property StatusTransition_FromApproved_ShouldNotAllowAnyTransition()
|
||
{
|
||
// Generate any target status
|
||
var targetStatusArb = Gen.Elements(
|
||
(int)AuditStatus.Pending,
|
||
(int)AuditStatus.Approved,
|
||
(int)AuditStatus.Rejected);
|
||
|
||
return Prop.ForAll(
|
||
targetStatusArb.ToArbitrary(),
|
||
targetStatus =>
|
||
{
|
||
// Act
|
||
var isValid = AdminProfileAuditService.IsValidStatusTransitionStatic(
|
||
(int)AuditStatus.Approved,
|
||
targetStatus);
|
||
|
||
// Assert - From Approved, should not allow any transition
|
||
return !isValid;
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 状态流转 - 从已拒绝可以流转到已通过(重新审核通过)
|
||
/// </summary>
|
||
[Fact]
|
||
public void StatusTransition_FromRejected_ToApproved_ShouldBeValid()
|
||
{
|
||
var isValid = AdminProfileAuditService.IsValidStatusTransitionStatic(
|
||
(int)AuditStatus.Rejected,
|
||
(int)AuditStatus.Approved);
|
||
|
||
Assert.True(isValid);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 状态流转 - 从已拒绝可以流转到已拒绝(更新拒绝原因)
|
||
/// </summary>
|
||
[Fact]
|
||
public void StatusTransition_FromRejected_ToRejected_ShouldBeValid()
|
||
{
|
||
var isValid = AdminProfileAuditService.IsValidStatusTransitionStatic(
|
||
(int)AuditStatus.Rejected,
|
||
(int)AuditStatus.Rejected);
|
||
|
||
Assert.True(isValid);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 状态流转 - 从已拒绝不能流转到待审核
|
||
/// </summary>
|
||
[Fact]
|
||
public void StatusTransition_FromRejected_ToPending_ShouldBeInvalid()
|
||
{
|
||
var isValid = AdminProfileAuditService.IsValidStatusTransitionStatic(
|
||
(int)AuditStatus.Rejected,
|
||
(int)AuditStatus.Pending);
|
||
|
||
Assert.False(isValid);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 状态流转 - 任何状态都不能手动流转到待审核
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public Property StatusTransition_ToPending_ShouldAlwaysBeInvalid()
|
||
{
|
||
// Generate any current status
|
||
var currentStatusArb = Gen.Elements(
|
||
(int)AuditStatus.Pending,
|
||
(int)AuditStatus.Approved,
|
||
(int)AuditStatus.Rejected);
|
||
|
||
return Prop.ForAll(
|
||
currentStatusArb.ToArbitrary(),
|
||
currentStatus =>
|
||
{
|
||
// Act
|
||
var isValid = AdminProfileAuditService.IsValidStatusTransitionStatic(
|
||
currentStatus,
|
||
(int)AuditStatus.Pending);
|
||
|
||
// Assert - Should never allow transition to Pending
|
||
return !isValid;
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 列表展示 - 只有已通过状态的资料才能在列表展示
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public Property CanDisplayInList_OnlyApprovedShouldBeDisplayable()
|
||
{
|
||
// Generate any audit status
|
||
var auditStatusArb = Gen.Elements(
|
||
(int)AuditStatus.Pending,
|
||
(int)AuditStatus.Approved,
|
||
(int)AuditStatus.Rejected);
|
||
|
||
return Prop.ForAll(
|
||
auditStatusArb.ToArbitrary(),
|
||
auditStatus =>
|
||
{
|
||
// Act
|
||
var canDisplay = AdminProfileAuditService.CanDisplayInList(auditStatus);
|
||
|
||
// Assert - Only Approved status should be displayable
|
||
var expectedResult = auditStatus == (int)AuditStatus.Approved;
|
||
return canDisplay == expectedResult;
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 列表展示 - 待审核状态不能展示
|
||
/// </summary>
|
||
[Fact]
|
||
public void CanDisplayInList_Pending_ShouldNotBeDisplayable()
|
||
{
|
||
var canDisplay = AdminProfileAuditService.CanDisplayInList((int)AuditStatus.Pending);
|
||
Assert.False(canDisplay);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 列表展示 - 已拒绝状态不能展示
|
||
/// </summary>
|
||
[Fact]
|
||
public void CanDisplayInList_Rejected_ShouldNotBeDisplayable()
|
||
{
|
||
var canDisplay = AdminProfileAuditService.CanDisplayInList((int)AuditStatus.Rejected);
|
||
Assert.False(canDisplay);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 列表展示 - 已通过状态可以展示
|
||
/// </summary>
|
||
[Fact]
|
||
public void CanDisplayInList_Approved_ShouldBeDisplayable()
|
||
{
|
||
var canDisplay = AdminProfileAuditService.CanDisplayInList((int)AuditStatus.Approved);
|
||
Assert.True(canDisplay);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 状态流转完整性 - 从待审核到已通过或已拒绝的流转应该是完整的
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public Property StatusTransition_CompleteWorkflow_ShouldBeValid()
|
||
{
|
||
// Generate a sequence of valid transitions
|
||
var workflowArb = Gen.Elements(
|
||
new[] { (int)AuditStatus.Pending, (int)AuditStatus.Approved },
|
||
new[] { (int)AuditStatus.Pending, (int)AuditStatus.Rejected },
|
||
new[] { (int)AuditStatus.Pending, (int)AuditStatus.Rejected, (int)AuditStatus.Approved },
|
||
new[] { (int)AuditStatus.Pending, (int)AuditStatus.Rejected, (int)AuditStatus.Rejected });
|
||
|
||
return Prop.ForAll(
|
||
workflowArb.ToArbitrary(),
|
||
workflow =>
|
||
{
|
||
// Verify each transition in the workflow is valid
|
||
for (int i = 0; i < workflow.Length - 1; i++)
|
||
{
|
||
var isValid = AdminProfileAuditService.IsValidStatusTransitionStatic(
|
||
workflow[i],
|
||
workflow[i + 1]);
|
||
if (!isValid) return false;
|
||
}
|
||
return true;
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 状态流转 - 无效状态值应该被拒绝
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public Property StatusTransition_InvalidStatusValues_ShouldBeRejected()
|
||
{
|
||
// Generate invalid status values (outside 0, 1, 2)
|
||
var invalidStatusArb = Gen.Choose(-10, 10)
|
||
.Where(s => s != 0 && s != 1 && s != 2);
|
||
|
||
var validStatusArb = Gen.Elements(0, 1, 2);
|
||
|
||
return Prop.ForAll(
|
||
invalidStatusArb.ToArbitrary(),
|
||
validStatusArb.ToArbitrary(),
|
||
(invalidStatus, validStatus) =>
|
||
{
|
||
// Act - Invalid current status
|
||
var isValid1 = AdminProfileAuditService.IsValidStatusTransitionStatic(
|
||
invalidStatus,
|
||
validStatus);
|
||
|
||
// Act - Invalid target status
|
||
var isValid2 = AdminProfileAuditService.IsValidStatusTransitionStatic(
|
||
validStatus,
|
||
invalidStatus);
|
||
|
||
// Assert - Both should be invalid
|
||
return !isValid1 && !isValid2;
|
||
});
|
||
}
|
||
}
|