mi-assessment/server/MiAssessment/tests/MiAssessment.Tests/Admin/CommissionPropertyTests.cs
zpc 6bf2ea595c feat(admin-business): 完成后台管理系统全部业务模块
- 系统配置管理模块 (Config)
- 内容管理模块 (Banner, Promotion)
- 测评管理模块 (Type, Question, Category, Mapping, Conclusion)
- 用户管理模块 (User)
- 订单管理模块 (Order)
- 规划师管理模块 (Planner)
- 分销管理模块 (InviteCode, Commission, Withdrawal)
- 数据统计仪表盘模块 (Dashboard)
- 权限控制集成
- 服务注册配置

全部381个测试通过
2026-02-03 20:50:51 +08:00

461 lines
18 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 Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using MiAssessment.Admin.Business.Data;
using MiAssessment.Admin.Business.Entities;
using MiAssessment.Admin.Business.Models.Distribution;
using MiAssessment.Admin.Business.Services;
using Moq;
using Xunit;
namespace MiAssessment.Tests.Admin;
/// <summary>
/// Commission 属性测试
/// 验证佣金服务的正确性属性
/// </summary>
public class CommissionPropertyTests
{
private readonly Mock<ILogger<DistributionService>> _mockLogger = new();
#region Property 14: Commission Statistics Accuracy
/// <summary>
/// Property 14: 佣金统计 - TotalAmount 等于所有 CommissionAmount 的总和
/// *For any* commission statistics query, the TotalAmount SHALL equal
/// the sum of all CommissionAmount values.
///
/// **Validates: Requirements 15.6**
/// </summary>
[Property(MaxTest = 100)]
public bool CommissionStatistics_TotalAmountEqualsSum(PositiveInt seed, PositiveInt count)
{
// Arrange: 创建多条佣金记录
using var dbContext = CreateDbContext();
var recordCount = (count.Get % 10) + 1; // 1-10条记录
var expectedTotal = 0m;
var userId = CreateTestUser(dbContext, seed.Get);
var fromUserId = CreateTestUser(dbContext, seed.Get + 1000);
var orderId = CreateTestOrder(dbContext, seed.Get, userId);
for (int i = 0; i < recordCount; i++)
{
var amount = ((seed.Get + i) % 100) + 1m; // 1-100
CreateTestCommission(dbContext, seed.Get + i, userId, fromUserId, orderId, amount, status: (i % 2) + 1);
expectedTotal += amount;
}
var service = new DistributionService(dbContext, _mockLogger.Object);
// Act: 获取统计数据
var statistics = service.GetCommissionStatisticsAsync(new CommissionStatisticsRequest()).GetAwaiter().GetResult();
// Assert: TotalAmount 应该等于所有 CommissionAmount 的总和
return statistics.TotalAmount == expectedTotal;
}
/// <summary>
/// Property 14: 佣金统计 - PendingAmount 等于状态为1的 CommissionAmount 总和
/// *For any* commission statistics query, the PendingAmount SHALL equal
/// the sum of CommissionAmount where Status is 1.
///
/// **Validates: Requirements 15.6**
/// </summary>
[Property(MaxTest = 100)]
public bool CommissionStatistics_PendingAmountEqualsStatusOneSum(PositiveInt seed, PositiveInt count)
{
// Arrange: 创建多条佣金记录,混合状态
using var dbContext = CreateDbContext();
var recordCount = (count.Get % 10) + 1; // 1-10条记录
var expectedPending = 0m;
var userId = CreateTestUser(dbContext, seed.Get);
var fromUserId = CreateTestUser(dbContext, seed.Get + 1000);
var orderId = CreateTestOrder(dbContext, seed.Get, userId);
for (int i = 0; i < recordCount; i++)
{
var amount = ((seed.Get + i) % 100) + 1m; // 1-100
var status = (i % 2) + 1; // 交替 1 和 2
CreateTestCommission(dbContext, seed.Get + i, userId, fromUserId, orderId, amount, status: status);
if (status == 1)
{
expectedPending += amount;
}
}
var service = new DistributionService(dbContext, _mockLogger.Object);
// Act: 获取统计数据
var statistics = service.GetCommissionStatisticsAsync(new CommissionStatisticsRequest()).GetAwaiter().GetResult();
// Assert: PendingAmount 应该等于状态为1的 CommissionAmount 总和
return statistics.PendingAmount == expectedPending;
}
/// <summary>
/// Property 14: 佣金统计 - SettledAmount 等于状态为2的 CommissionAmount 总和
/// *For any* commission statistics query, the SettledAmount SHALL equal
/// the sum of CommissionAmount where Status is 2.
///
/// **Validates: Requirements 15.6**
/// </summary>
[Property(MaxTest = 100)]
public bool CommissionStatistics_SettledAmountEqualsStatusTwoSum(PositiveInt seed, PositiveInt count)
{
// Arrange: 创建多条佣金记录,混合状态
using var dbContext = CreateDbContext();
var recordCount = (count.Get % 10) + 1; // 1-10条记录
var expectedSettled = 0m;
var userId = CreateTestUser(dbContext, seed.Get);
var fromUserId = CreateTestUser(dbContext, seed.Get + 1000);
var orderId = CreateTestOrder(dbContext, seed.Get, userId);
for (int i = 0; i < recordCount; i++)
{
var amount = ((seed.Get + i) % 100) + 1m; // 1-100
var status = (i % 2) + 1; // 交替 1 和 2
CreateTestCommission(dbContext, seed.Get + i, userId, fromUserId, orderId, amount, status: status);
if (status == 2)
{
expectedSettled += amount;
}
}
var service = new DistributionService(dbContext, _mockLogger.Object);
// Act: 获取统计数据
var statistics = service.GetCommissionStatisticsAsync(new CommissionStatisticsRequest()).GetAwaiter().GetResult();
// Assert: SettledAmount 应该等于状态为2的 CommissionAmount 总和
return statistics.SettledAmount == expectedSettled;
}
/// <summary>
/// Property 14: 佣金统计 - TotalAmount 等于 PendingAmount + SettledAmount
/// *For any* commission statistics query, TotalAmount SHALL equal
/// PendingAmount + SettledAmount.
///
/// **Validates: Requirements 15.6**
/// </summary>
[Property(MaxTest = 100)]
public bool CommissionStatistics_TotalEqualsPendingPlusSettled(PositiveInt seed, PositiveInt count)
{
// Arrange: 创建多条佣金记录
using var dbContext = CreateDbContext();
var recordCount = (count.Get % 10) + 1; // 1-10条记录
var userId = CreateTestUser(dbContext, seed.Get);
var fromUserId = CreateTestUser(dbContext, seed.Get + 1000);
var orderId = CreateTestOrder(dbContext, seed.Get, userId);
for (int i = 0; i < recordCount; i++)
{
var amount = ((seed.Get + i) % 100) + 1m; // 1-100
var status = (i % 2) + 1; // 交替 1 和 2
CreateTestCommission(dbContext, seed.Get + i, userId, fromUserId, orderId, amount, status: status);
}
var service = new DistributionService(dbContext, _mockLogger.Object);
// Act: 获取统计数据
var statistics = service.GetCommissionStatisticsAsync(new CommissionStatisticsRequest()).GetAwaiter().GetResult();
// Assert: TotalAmount 应该等于 PendingAmount + SettledAmount
return statistics.TotalAmount == statistics.PendingAmount + statistics.SettledAmount;
}
/// <summary>
/// Property 14: 佣金统计 - TotalCount 等于所有记录数
/// *For any* commission statistics query, TotalCount SHALL equal
/// the count of all commission records.
///
/// **Validates: Requirements 15.6**
/// </summary>
[Property(MaxTest = 100)]
public bool CommissionStatistics_TotalCountEqualsRecordCount(PositiveInt seed, PositiveInt count)
{
// Arrange: 创建多条佣金记录
using var dbContext = CreateDbContext();
var recordCount = (count.Get % 10) + 1; // 1-10条记录
var userId = CreateTestUser(dbContext, seed.Get);
var fromUserId = CreateTestUser(dbContext, seed.Get + 1000);
var orderId = CreateTestOrder(dbContext, seed.Get, userId);
for (int i = 0; i < recordCount; i++)
{
var amount = ((seed.Get + i) % 100) + 1m;
var status = (i % 2) + 1;
CreateTestCommission(dbContext, seed.Get + i, userId, fromUserId, orderId, amount, status: status);
}
var service = new DistributionService(dbContext, _mockLogger.Object);
// Act: 获取统计数据
var statistics = service.GetCommissionStatisticsAsync(new CommissionStatisticsRequest()).GetAwaiter().GetResult();
// Assert: TotalCount 应该等于记录数
return statistics.TotalCount == recordCount;
}
/// <summary>
/// Property 14: 佣金统计 - TotalCount 等于 PendingCount + SettledCount
/// *For any* commission statistics query, TotalCount SHALL equal
/// PendingCount + SettledCount.
///
/// **Validates: Requirements 15.6**
/// </summary>
[Property(MaxTest = 100)]
public bool CommissionStatistics_TotalCountEqualsPendingPlusSettledCount(PositiveInt seed, PositiveInt count)
{
// Arrange: 创建多条佣金记录
using var dbContext = CreateDbContext();
var recordCount = (count.Get % 10) + 1; // 1-10条记录
var userId = CreateTestUser(dbContext, seed.Get);
var fromUserId = CreateTestUser(dbContext, seed.Get + 1000);
var orderId = CreateTestOrder(dbContext, seed.Get, userId);
for (int i = 0; i < recordCount; i++)
{
var amount = ((seed.Get + i) % 100) + 1m;
var status = (i % 2) + 1;
CreateTestCommission(dbContext, seed.Get + i, userId, fromUserId, orderId, amount, status: status);
}
var service = new DistributionService(dbContext, _mockLogger.Object);
// Act: 获取统计数据
var statistics = service.GetCommissionStatisticsAsync(new CommissionStatisticsRequest()).GetAwaiter().GetResult();
// Assert: TotalCount 应该等于 PendingCount + SettledCount
return statistics.TotalCount == statistics.PendingCount + statistics.SettledCount;
}
/// <summary>
/// Property 14: 佣金统计 - 按用户ID筛选时统计正确
/// *For any* commission statistics query with UserId filter,
/// the statistics SHALL only include records for that user.
///
/// **Validates: Requirements 15.6**
/// </summary>
[Property(MaxTest = 100)]
public bool CommissionStatistics_FilterByUserIdCorrect(PositiveInt seed)
{
// Arrange: 创建两个用户的佣金记录
using var dbContext = CreateDbContext();
var userId1 = CreateTestUser(dbContext, seed.Get);
var userId2 = CreateTestUser(dbContext, seed.Get + 500);
var fromUserId = CreateTestUser(dbContext, seed.Get + 1000);
var orderId = CreateTestOrder(dbContext, seed.Get, userId1);
// 用户1的佣金记录
var user1Amount1 = ((seed.Get) % 100) + 1m;
var user1Amount2 = ((seed.Get + 1) % 100) + 1m;
CreateTestCommission(dbContext, seed.Get, userId1, fromUserId, orderId, user1Amount1, status: 1);
CreateTestCommission(dbContext, seed.Get + 1, userId1, fromUserId, orderId, user1Amount2, status: 2);
// 用户2的佣金记录
var user2Amount = ((seed.Get + 2) % 100) + 1m;
CreateTestCommission(dbContext, seed.Get + 2, userId2, fromUserId, orderId, user2Amount, status: 1);
var service = new DistributionService(dbContext, _mockLogger.Object);
// Act: 按用户1筛选获取统计数据
var statistics = service.GetCommissionStatisticsAsync(new CommissionStatisticsRequest { UserId = userId1 }).GetAwaiter().GetResult();
// Assert: 统计数据应该只包含用户1的记录
var expectedTotal = user1Amount1 + user1Amount2;
return statistics.TotalAmount == expectedTotal
&& statistics.TotalCount == 2
&& statistics.PendingAmount == user1Amount1
&& statistics.SettledAmount == user1Amount2;
}
/// <summary>
/// Property 14: 佣金统计 - 空数据时返回零值
/// *For any* commission statistics query with no matching records,
/// all statistics values SHALL be zero.
///
/// **Validates: Requirements 15.6**
/// </summary>
[Property(MaxTest = 50)]
public bool CommissionStatistics_EmptyDataReturnsZero(PositiveInt seed)
{
// Arrange: 创建空数据库
using var dbContext = CreateDbContext();
var service = new DistributionService(dbContext, _mockLogger.Object);
// Act: 获取统计数据
var statistics = service.GetCommissionStatisticsAsync(new CommissionStatisticsRequest()).GetAwaiter().GetResult();
// Assert: 所有统计值应该为零
return statistics.TotalAmount == 0m
&& statistics.PendingAmount == 0m
&& statistics.SettledAmount == 0m
&& statistics.TotalCount == 0
&& statistics.PendingCount == 0
&& statistics.SettledCount == 0;
}
/// <summary>
/// Property 14: 佣金统计 - 软删除记录不计入统计
/// *For any* commission statistics query, soft-deleted records
/// SHALL NOT be included in the statistics.
///
/// **Validates: Requirements 15.6**
/// </summary>
[Property(MaxTest = 100)]
public bool CommissionStatistics_SoftDeletedNotIncluded(PositiveInt seed)
{
// Arrange: 创建佣金记录,部分软删除
using var dbContext = CreateDbContext();
var userId = CreateTestUser(dbContext, seed.Get);
var fromUserId = CreateTestUser(dbContext, seed.Get + 1000);
var orderId = CreateTestOrder(dbContext, seed.Get, userId);
// 正常记录
var normalAmount = ((seed.Get) % 100) + 1m;
CreateTestCommission(dbContext, seed.Get, userId, fromUserId, orderId, normalAmount, status: 1, isDeleted: false);
// 软删除记录
var deletedAmount = ((seed.Get + 1) % 100) + 1m;
CreateTestCommission(dbContext, seed.Get + 1, userId, fromUserId, orderId, deletedAmount, status: 1, isDeleted: true);
var service = new DistributionService(dbContext, _mockLogger.Object);
// Act: 获取统计数据
var statistics = service.GetCommissionStatisticsAsync(new CommissionStatisticsRequest()).GetAwaiter().GetResult();
// Assert: 统计数据应该只包含正常记录
return statistics.TotalAmount == normalAmount
&& statistics.TotalCount == 1;
}
#endregion
#region
/// <summary>
/// 创建内存数据库上下文
/// </summary>
private AdminBusinessDbContext CreateDbContext()
{
var options = new DbContextOptionsBuilder<AdminBusinessDbContext>()
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
.Options;
return new AdminBusinessDbContext(options);
}
/// <summary>
/// 创建测试用户
/// </summary>
/// <param name="dbContext">数据库上下文</param>
/// <param name="seed">随机种子</param>
/// <returns>用户ID</returns>
private long CreateTestUser(AdminBusinessDbContext dbContext, int seed)
{
var user = new User
{
Uid = $"{seed % 1000000:D6}",
OpenId = $"openid_{seed}",
Phone = $"138{seed % 100000000:D8}",
Nickname = $"User_{seed}",
UserLevel = 1,
Status = 1,
CreateTime = DateTime.Now,
UpdateTime = DateTime.Now,
IsDeleted = false
};
dbContext.Users.Add(user);
dbContext.SaveChanges();
return user.Id;
}
/// <summary>
/// 创建测试订单
/// </summary>
/// <param name="dbContext">数据库上下文</param>
/// <param name="seed">随机种子</param>
/// <param name="userId">用户ID</param>
/// <returns>订单ID</returns>
private long CreateTestOrder(AdminBusinessDbContext dbContext, int seed, long userId)
{
var order = new Order
{
OrderNo = $"ORD{DateTime.Now:yyyyMMddHHmmss}{seed % 10000:D4}",
UserId = userId,
OrderType = (seed % 2) + 1,
ProductId = seed % 100 + 1,
ProductName = $"测试商品_{seed}",
Amount = 100m,
PayAmount = 100m,
PayType = 1,
Status = 2,
PayTime = DateTime.Now.AddMinutes(-seed % 60),
CreateTime = DateTime.Now.AddDays(-seed % 30),
UpdateTime = DateTime.Now,
IsDeleted = false
};
dbContext.Orders.Add(order);
dbContext.SaveChanges();
return order.Id;
}
/// <summary>
/// 创建测试佣金记录
/// </summary>
/// <param name="dbContext">数据库上下文</param>
/// <param name="seed">随机种子</param>
/// <param name="userId">获得佣金的用户ID</param>
/// <param name="fromUserId">来源用户ID</param>
/// <param name="orderId">订单ID</param>
/// <param name="amount">佣金金额</param>
/// <param name="status">状态1待结算 2已结算</param>
/// <param name="isDeleted">是否软删除</param>
/// <returns>佣金记录ID</returns>
private long CreateTestCommission(
AdminBusinessDbContext dbContext,
int seed,
long userId,
long fromUserId,
long orderId,
decimal amount,
int status = 1,
bool isDeleted = false)
{
var commission = new Commission
{
UserId = userId,
FromUserId = fromUserId,
OrderId = orderId,
OrderAmount = amount * 10, // 订单金额是佣金的10倍
CommissionRate = 0.1m, // 10%佣金比例
CommissionAmount = amount,
Level = (seed % 2) + 1, // 1或2
Status = status,
SettleTime = status == 2 ? DateTime.Now : null,
CreateTime = DateTime.Now.AddDays(-seed % 30),
UpdateTime = DateTime.Now,
IsDeleted = isDeleted
};
dbContext.Commissions.Add(commission);
dbContext.SaveChanges();
return commission.Id;
}
#endregion
}