- 系统配置管理模块 (Config) - 内容管理模块 (Banner, Promotion) - 测评管理模块 (Type, Question, Category, Mapping, Conclusion) - 用户管理模块 (User) - 订单管理模块 (Order) - 规划师管理模块 (Planner) - 分销管理模块 (InviteCode, Commission, Withdrawal) - 数据统计仪表盘模块 (Dashboard) - 权限控制集成 - 服务注册配置 全部381个测试通过
379 lines
13 KiB
C#
379 lines
13 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.User;
|
|
using MiAssessment.Admin.Business.Services;
|
|
using Moq;
|
|
using Xunit;
|
|
|
|
namespace MiAssessment.Tests.Admin;
|
|
|
|
/// <summary>
|
|
/// User 属性测试
|
|
/// 验证用户服务的正确性属性
|
|
/// </summary>
|
|
public class UserPropertyTests
|
|
{
|
|
private readonly Mock<ILogger<UserBusinessService>> _mockLogger = new();
|
|
|
|
#region Property 3: Pagination Correctness
|
|
|
|
/// <summary>
|
|
/// Property 3: 分页查询返回的记录数不超过 PageSize
|
|
/// *For any* paginated list query with PageIndex and PageSize parameters,
|
|
/// the result SHALL contain at most PageSize items.
|
|
///
|
|
/// **Validates: Requirements 9.1**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool PaginationCorrectness_ResultCountNotExceedPageSize(PositiveInt seed, PositiveInt pageSize)
|
|
{
|
|
// Arrange: 创建包含多个用户的数据库
|
|
using var dbContext = CreateDbContext();
|
|
var userCount = (seed.Get % 50) + 1; // 1-50 个用户
|
|
var actualPageSize = Math.Min(pageSize.Get, 100); // PageSize 最大 100
|
|
|
|
CreateTestUsers(dbContext, userCount, seed.Get);
|
|
var service = new UserBusinessService(dbContext, _mockLogger.Object);
|
|
|
|
// Act: 执行分页查询
|
|
var request = new UserQueryRequest
|
|
{
|
|
Page = 1,
|
|
PageSize = actualPageSize
|
|
};
|
|
var result = service.GetUserListAsync(request).GetAwaiter().GetResult();
|
|
|
|
// Assert: 返回的记录数不超过 PageSize
|
|
return result.List.Count <= actualPageSize;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 3: Total 等于数据库中匹配记录的实际数量
|
|
/// *For any* paginated list query, the Total count SHALL equal
|
|
/// the actual number of matching records in the database.
|
|
///
|
|
/// **Validates: Requirements 9.1**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool PaginationCorrectness_TotalEqualsActualCount(PositiveInt seed)
|
|
{
|
|
// Arrange: 创建包含多个用户的数据库
|
|
using var dbContext = CreateDbContext();
|
|
var userCount = (seed.Get % 50) + 1; // 1-50 个用户
|
|
|
|
CreateTestUsers(dbContext, userCount, seed.Get);
|
|
var service = new UserBusinessService(dbContext, _mockLogger.Object);
|
|
|
|
// 计算数据库中实际的非删除用户数量
|
|
var actualCount = dbContext.Users.Count(u => !u.IsDeleted);
|
|
|
|
// Act: 执行分页查询
|
|
var request = new UserQueryRequest { Page = 1, PageSize = 10 };
|
|
var result = service.GetUserListAsync(request).GetAwaiter().GetResult();
|
|
|
|
// Assert: Total 等于实际数量
|
|
return result.Total == actualCount;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 3: 分页查询在不同页码下返回正确的记录数
|
|
///
|
|
/// **Validates: Requirements 9.1**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool PaginationCorrectness_DifferentPagesReturnCorrectCount(PositiveInt seed)
|
|
{
|
|
// Arrange: 创建固定数量的用户
|
|
using var dbContext = CreateDbContext();
|
|
var userCount = 25; // 固定 25 个用户
|
|
var pageSize = 10;
|
|
|
|
CreateTestUsers(dbContext, userCount, seed.Get);
|
|
var service = new UserBusinessService(dbContext, _mockLogger.Object);
|
|
|
|
// Act: 查询第一页
|
|
var request1 = new UserQueryRequest { Page = 1, PageSize = pageSize };
|
|
var result1 = service.GetUserListAsync(request1).GetAwaiter().GetResult();
|
|
|
|
// 查询第二页
|
|
var request2 = new UserQueryRequest { Page = 2, PageSize = pageSize };
|
|
var result2 = service.GetUserListAsync(request2).GetAwaiter().GetResult();
|
|
|
|
// 查询第三页
|
|
var request3 = new UserQueryRequest { Page = 3, PageSize = pageSize };
|
|
var result3 = service.GetUserListAsync(request3).GetAwaiter().GetResult();
|
|
|
|
// Assert:
|
|
// 第一页应该有 10 条记录
|
|
// 第二页应该有 10 条记录
|
|
// 第三页应该有 5 条记录
|
|
return result1.List.Count == 10
|
|
&& result2.List.Count == 10
|
|
&& result3.List.Count == 5
|
|
&& result1.Total == 25
|
|
&& result2.Total == 25
|
|
&& result3.Total == 25;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 3: 超出范围的页码返回空列表
|
|
///
|
|
/// **Validates: Requirements 9.1**
|
|
/// </summary>
|
|
[Property(MaxTest = 50)]
|
|
public bool PaginationCorrectness_OutOfRangePageReturnsEmpty(PositiveInt seed)
|
|
{
|
|
// Arrange: 创建少量用户
|
|
using var dbContext = CreateDbContext();
|
|
var userCount = 5;
|
|
|
|
CreateTestUsers(dbContext, userCount, seed.Get);
|
|
var service = new UserBusinessService(dbContext, _mockLogger.Object);
|
|
|
|
// Act: 查询超出范围的页码
|
|
var request = new UserQueryRequest { Page = 100, PageSize = 10 };
|
|
var result = service.GetUserListAsync(request).GetAwaiter().GetResult();
|
|
|
|
// Assert: 返回空列表,但 Total 仍然正确
|
|
return result.List.Count == 0 && result.Total == userCount;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 3: 带筛选条件的分页查询 Total 正确
|
|
///
|
|
/// **Validates: Requirements 9.1**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool PaginationCorrectness_FilteredQueryTotalCorrect(PositiveInt seed)
|
|
{
|
|
// Arrange: 创建不同状态的用户
|
|
using var dbContext = CreateDbContext();
|
|
var activeCount = (seed.Get % 10) + 1;
|
|
var disabledCount = (seed.Get % 5) + 1;
|
|
|
|
// 创建启用状态的用户
|
|
for (int i = 0; i < activeCount; i++)
|
|
{
|
|
CreateTestUserWithStatus(dbContext, seed.Get + i, 1);
|
|
}
|
|
// 创建禁用状态的用户
|
|
for (int i = 0; i < disabledCount; i++)
|
|
{
|
|
CreateTestUserWithStatus(dbContext, seed.Get + activeCount + i, 0);
|
|
}
|
|
|
|
var service = new UserBusinessService(dbContext, _mockLogger.Object);
|
|
|
|
// Act: 查询启用状态的用户
|
|
var request = new UserQueryRequest { Page = 1, PageSize = 100, Status = 1 };
|
|
var result = service.GetUserListAsync(request).GetAwaiter().GetResult();
|
|
|
|
// Assert: Total 等于启用状态的用户数量
|
|
return result.Total == activeCount;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 3: 带用户等级筛选的分页查询 Total 正确
|
|
///
|
|
/// **Validates: Requirements 9.1**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool PaginationCorrectness_UserLevelFilterTotalCorrect(PositiveInt seed)
|
|
{
|
|
// Arrange: 创建不同等级的用户
|
|
using var dbContext = CreateDbContext();
|
|
var normalCount = (seed.Get % 10) + 1;
|
|
var partnerCount = (seed.Get % 5) + 1;
|
|
|
|
// 创建普通用户
|
|
for (int i = 0; i < normalCount; i++)
|
|
{
|
|
CreateTestUserWithLevel(dbContext, seed.Get + i, 1);
|
|
}
|
|
// 创建合伙人
|
|
for (int i = 0; i < partnerCount; i++)
|
|
{
|
|
CreateTestUserWithLevel(dbContext, seed.Get + normalCount + i, 2);
|
|
}
|
|
|
|
var service = new UserBusinessService(dbContext, _mockLogger.Object);
|
|
|
|
// Act: 查询合伙人
|
|
var request = new UserQueryRequest { Page = 1, PageSize = 100, UserLevel = 2 };
|
|
var result = service.GetUserListAsync(request).GetAwaiter().GetResult();
|
|
|
|
// Assert: Total 等于合伙人数量
|
|
return result.Total == partnerCount;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 3: 软删除的用户不计入 Total
|
|
///
|
|
/// **Validates: Requirements 9.1**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool PaginationCorrectness_DeletedUsersNotInTotal(PositiveInt seed)
|
|
{
|
|
// Arrange: 创建用户,部分软删除
|
|
using var dbContext = CreateDbContext();
|
|
var activeCount = (seed.Get % 10) + 1;
|
|
var deletedCount = (seed.Get % 5) + 1;
|
|
|
|
// 创建正常用户
|
|
for (int i = 0; i < activeCount; i++)
|
|
{
|
|
CreateTestUser(dbContext, seed.Get + i, false);
|
|
}
|
|
// 创建已删除用户
|
|
for (int i = 0; i < deletedCount; i++)
|
|
{
|
|
CreateTestUser(dbContext, seed.Get + activeCount + i, true);
|
|
}
|
|
|
|
var service = new UserBusinessService(dbContext, _mockLogger.Object);
|
|
|
|
// Act: 查询用户列表
|
|
var request = new UserQueryRequest { Page = 1, PageSize = 100 };
|
|
var result = service.GetUserListAsync(request).GetAwaiter().GetResult();
|
|
|
|
// Assert: Total 只包含未删除的用户
|
|
return result.Total == activeCount;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 3: TotalPages 计算正确
|
|
///
|
|
/// **Validates: Requirements 9.1**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool PaginationCorrectness_TotalPagesCalculatedCorrectly(PositiveInt seed, PositiveInt pageSize)
|
|
{
|
|
// Arrange
|
|
using var dbContext = CreateDbContext();
|
|
var userCount = (seed.Get % 100) + 1;
|
|
var actualPageSize = Math.Max(1, Math.Min(pageSize.Get, 100));
|
|
|
|
CreateTestUsers(dbContext, userCount, seed.Get);
|
|
var service = new UserBusinessService(dbContext, _mockLogger.Object);
|
|
|
|
// Act
|
|
var request = new UserQueryRequest { Page = 1, PageSize = actualPageSize };
|
|
var result = service.GetUserListAsync(request).GetAwaiter().GetResult();
|
|
|
|
// Assert: TotalPages = ceil(Total / PageSize)
|
|
var expectedTotalPages = (int)Math.Ceiling((double)result.Total / actualPageSize);
|
|
return result.TotalPages == expectedTotalPages;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 辅助方法
|
|
|
|
/// <summary>
|
|
/// 创建内存数据库上下文
|
|
/// </summary>
|
|
private AdminBusinessDbContext CreateDbContext()
|
|
{
|
|
var options = new DbContextOptionsBuilder<AdminBusinessDbContext>()
|
|
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
|
|
.Options;
|
|
|
|
return new AdminBusinessDbContext(options);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 创建多个测试用户
|
|
/// </summary>
|
|
private void CreateTestUsers(AdminBusinessDbContext dbContext, int count, int seed)
|
|
{
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
CreateTestUser(dbContext, seed + i, false);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 创建测试用户
|
|
/// </summary>
|
|
private long CreateTestUser(AdminBusinessDbContext dbContext, int seed, bool isDeleted)
|
|
{
|
|
var user = new User
|
|
{
|
|
Uid = $"{seed % 1000000:D6}",
|
|
OpenId = $"openid_{seed}",
|
|
Phone = $"138{seed % 100000000:D8}",
|
|
Nickname = $"User_{seed}",
|
|
Avatar = $"https://example.com/avatar_{seed}.jpg",
|
|
UserLevel = 1,
|
|
Balance = seed % 1000,
|
|
TotalIncome = seed % 5000,
|
|
WithdrawnAmount = seed % 500,
|
|
Status = 1,
|
|
CreateTime = DateTime.Now.AddDays(-seed % 365),
|
|
UpdateTime = DateTime.Now,
|
|
IsDeleted = isDeleted
|
|
};
|
|
dbContext.Users.Add(user);
|
|
dbContext.SaveChanges();
|
|
return user.Id;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 创建指定状态的测试用户
|
|
/// </summary>
|
|
private long CreateTestUserWithStatus(AdminBusinessDbContext dbContext, int seed, int status)
|
|
{
|
|
var user = new User
|
|
{
|
|
Uid = $"{seed % 1000000:D6}",
|
|
OpenId = $"openid_{seed}",
|
|
Phone = $"138{seed % 100000000:D8}",
|
|
Nickname = $"User_{seed}",
|
|
Avatar = $"https://example.com/avatar_{seed}.jpg",
|
|
UserLevel = 1,
|
|
Balance = seed % 1000,
|
|
TotalIncome = seed % 5000,
|
|
WithdrawnAmount = seed % 500,
|
|
Status = status,
|
|
CreateTime = DateTime.Now.AddDays(-seed % 365),
|
|
UpdateTime = DateTime.Now,
|
|
IsDeleted = false
|
|
};
|
|
dbContext.Users.Add(user);
|
|
dbContext.SaveChanges();
|
|
return user.Id;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 创建指定等级的测试用户
|
|
/// </summary>
|
|
private long CreateTestUserWithLevel(AdminBusinessDbContext dbContext, int seed, int userLevel)
|
|
{
|
|
var user = new User
|
|
{
|
|
Uid = $"{seed % 1000000:D6}",
|
|
OpenId = $"openid_{seed}",
|
|
Phone = $"138{seed % 100000000:D8}",
|
|
Nickname = $"User_{seed}",
|
|
Avatar = $"https://example.com/avatar_{seed}.jpg",
|
|
UserLevel = userLevel,
|
|
Balance = seed % 1000,
|
|
TotalIncome = seed % 5000,
|
|
WithdrawnAmount = seed % 500,
|
|
Status = 1,
|
|
CreateTime = DateTime.Now.AddDays(-seed % 365),
|
|
UpdateTime = DateTime.Now,
|
|
IsDeleted = false
|
|
};
|
|
dbContext.Users.Add(user);
|
|
dbContext.SaveChanges();
|
|
return user.Id;
|
|
}
|
|
|
|
#endregion
|
|
}
|