xiangyixiangqin/server/tests/XiangYi.Application.Tests/Services/AdminProfileAuditServicePropertyTests.cs
2026-01-02 18:00:49 +08:00

265 lines
8.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
});
}
}