mi-assessment/server/MiAssessment/tests/MiAssessment.Tests/Admin/UserPropertyTests.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

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
}