- 系统配置管理模块 (Config) - 内容管理模块 (Banner, Promotion) - 测评管理模块 (Type, Question, Category, Mapping, Conclusion) - 用户管理模块 (User) - 订单管理模块 (Order) - 规划师管理模块 (Planner) - 分销管理模块 (InviteCode, Commission, Withdrawal) - 数据统计仪表盘模块 (Dashboard) - 权限控制集成 - 服务注册配置 全部381个测试通过
461 lines
18 KiB
C#
461 lines
18 KiB
C#
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
|
||
}
|