mi-assessment/server/MiAssessment/tests/MiAssessment.Tests/Admin/AssessmentRecordServiceTests.cs
2026-02-08 11:31:08 +08:00

427 lines
14 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 Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using MiAssessment.Admin.Business.Data;
using MiAssessment.Admin.Business.Entities;
using MiAssessment.Admin.Business.Models;
using MiAssessment.Admin.Business.Models.AssessmentRecord;
using MiAssessment.Admin.Business.Models.Common;
using MiAssessment.Admin.Business.Services;
using Moq;
using Xunit;
namespace MiAssessment.Tests.Admin;
/// <summary>
/// 测评记录服务单元测试
/// 验证测评记录服务的边界条件和错误处理
/// </summary>
public class AssessmentRecordServiceTests
{
private readonly Mock<ILogger<AssessmentRecordService>> _mockLogger = new();
#region (Requirements 2.4)
/// <summary>
/// 测试 GetRecordDetailAsync 当记录 ID 不存在时返回 null
/// **Validates: Requirements 2.4**
/// </summary>
[Fact]
public async Task GetRecordDetailAsync_WithNonExistentId_ReturnsNull()
{
// Arrange
using var dbContext = CreateDbContext();
var service = new AssessmentRecordService(dbContext, _mockLogger.Object);
var nonExistentId = 99999L;
// Act
var result = await service.GetRecordDetailAsync(nonExistentId);
// Assert
Assert.Null(result);
}
/// <summary>
/// 测试 GetRecordDetailAsync 当记录已软删除时返回 null
/// **Validates: Requirements 2.4**
/// </summary>
[Fact]
public async Task GetRecordDetailAsync_WithSoftDeletedRecord_ReturnsNull()
{
// Arrange
using var dbContext = CreateDbContext();
var user = CreateTestUser(dbContext, 1);
var order = CreateTestOrder(dbContext, user.Id, 1);
var assessmentType = CreateTestAssessmentType(dbContext, 1);
// 创建一个已软删除的记录
var record = new AssessmentRecord
{
UserId = user.Id,
OrderId = order.Id,
AssessmentTypeId = assessmentType.Id,
Name = "测试人",
Phone = "13900000001",
Gender = 1,
Age = 15,
EducationStage = 2,
Province = "北京市",
City = "北京市",
District = "朝阳区",
Status = 4,
CreateTime = DateTime.Now,
UpdateTime = DateTime.Now,
IsDeleted = true // 已软删除
};
dbContext.AssessmentRecords.Add(record);
await dbContext.SaveChangesAsync();
var service = new AssessmentRecordService(dbContext, _mockLogger.Object);
// Act
var result = await service.GetRecordDetailAsync(record.Id);
// Assert
Assert.Null(result);
}
/// <summary>
/// 测试 GetRecordReportAsync 当记录 ID 不存在时返回 null
/// **Validates: Requirements 2.4**
/// </summary>
[Fact]
public async Task GetRecordReportAsync_WithNonExistentId_ReturnsNull()
{
// Arrange
using var dbContext = CreateDbContext();
var service = new AssessmentRecordService(dbContext, _mockLogger.Object);
var nonExistentId = 99999L;
// Act
var result = await service.GetRecordReportAsync(nonExistentId);
// Assert
Assert.Null(result);
}
#endregion
#region (Requirements 3.3)
/// <summary>
/// 测试 GetRecordReportAsync 当记录状态为 1待测评时返回 null
/// **Validates: Requirements 3.3**
/// </summary>
[Fact]
public async Task GetRecordReportAsync_WithStatus1_ReturnsNull()
{
// Arrange
using var dbContext = CreateDbContext();
var record = await CreateTestRecordWithStatus(dbContext, 1, 1); // Status = 1 (待测评)
var service = new AssessmentRecordService(dbContext, _mockLogger.Object);
// Act
var result = await service.GetRecordReportAsync(record.Id);
// Assert
Assert.Null(result);
}
/// <summary>
/// 测试 GetRecordReportAsync 当记录状态为 2测评中时返回 null
/// **Validates: Requirements 3.3**
/// </summary>
[Fact]
public async Task GetRecordReportAsync_WithStatus2_ReturnsNull()
{
// Arrange
using var dbContext = CreateDbContext();
var record = await CreateTestRecordWithStatus(dbContext, 2, 2); // Status = 2 (测评中)
var service = new AssessmentRecordService(dbContext, _mockLogger.Object);
// Act
var result = await service.GetRecordReportAsync(record.Id);
// Assert
Assert.Null(result);
}
/// <summary>
/// 测试 GetRecordReportAsync 当记录状态为 3生成中时返回 null
/// **Validates: Requirements 3.3**
/// </summary>
[Fact]
public async Task GetRecordReportAsync_WithStatus3_ReturnsNull()
{
// Arrange
using var dbContext = CreateDbContext();
var record = await CreateTestRecordWithStatus(dbContext, 3, 3); // Status = 3 (生成中)
var service = new AssessmentRecordService(dbContext, _mockLogger.Object);
// Act
var result = await service.GetRecordReportAsync(record.Id);
// Assert
Assert.Null(result);
}
/// <summary>
/// 测试 GetRecordReportAsync 当记录状态为 4已完成时返回报告
/// **Validates: Requirements 3.3**
/// </summary>
[Fact]
public async Task GetRecordReportAsync_WithStatus4_ReturnsReport()
{
// Arrange
using var dbContext = CreateDbContext();
var record = await CreateTestRecordWithStatus(dbContext, 4, 4); // Status = 4 (已完成)
var service = new AssessmentRecordService(dbContext, _mockLogger.Object);
// Act
var result = await service.GetRecordReportAsync(record.Id);
// Assert
Assert.NotNull(result);
Assert.Equal(record.Id, result.Id);
Assert.Equal(4, result.Status);
Assert.Equal("已完成", result.StatusName);
}
#endregion
#region (Requirements 4.3)
/// <summary>
/// 测试 ExportRecordsAsync 当结果集超过 10000 条记录时抛出 BusinessException
/// **Validates: Requirements 4.3**
/// </summary>
[Fact]
public async Task ExportRecordsAsync_WithExceedingLimit_ThrowsBusinessException()
{
// Arrange
using var dbContext = CreateDbContext();
// 创建超过 10000 条记录
await CreateBulkTestRecords(dbContext, 10001);
var service = new AssessmentRecordService(dbContext, _mockLogger.Object);
var request = new AssessmentRecordQueryRequest { Page = 1, PageSize = 100 };
// Act & Assert
var exception = await Assert.ThrowsAsync<BusinessException>(
() => service.ExportRecordsAsync(request));
Assert.Equal(ErrorCodes.ExportDataTooLarge, exception.Code);
Assert.Equal("导出数据量过大,请缩小查询范围", exception.Message);
}
/// <summary>
/// 测试 ExportRecordsAsync 当结果集正好为 10000 条记录时不抛出异常
/// **Validates: Requirements 4.3**
/// </summary>
[Fact]
public async Task ExportRecordsAsync_WithExactLimit_DoesNotThrow()
{
// Arrange
using var dbContext = CreateDbContext();
// 创建正好 10000 条记录
await CreateBulkTestRecords(dbContext, 10000);
var service = new AssessmentRecordService(dbContext, _mockLogger.Object);
var request = new AssessmentRecordQueryRequest { Page = 1, PageSize = 100 };
// Act
var result = await service.ExportRecordsAsync(request);
// Assert
Assert.NotNull(result);
Assert.True(result.Length > 0);
}
/// <summary>
/// 测试 ExportRecordsAsync 当结果集少于 10000 条记录时正常导出
/// **Validates: Requirements 4.3**
/// </summary>
[Fact]
public async Task ExportRecordsAsync_WithinLimit_ReturnsExcelBytes()
{
// Arrange
using var dbContext = CreateDbContext();
// 创建少量记录
await CreateBulkTestRecords(dbContext, 100);
var service = new AssessmentRecordService(dbContext, _mockLogger.Object);
var request = new AssessmentRecordQueryRequest { Page = 1, PageSize = 100 };
// Act
var result = await service.ExportRecordsAsync(request);
// Assert
Assert.NotNull(result);
Assert.True(result.Length > 0);
// 验证是有效的 Excel 文件XLSX 文件以 PK 开头,因为它是 ZIP 格式)
Assert.Equal(0x50, result[0]); // 'P'
Assert.Equal(0x4B, result[1]); // 'K'
}
#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 User CreateTestUser(AdminBusinessDbContext dbContext, int seed)
{
var user = new User
{
Uid = $"{seed % 1000000:D6}",
OpenId = $"openid_{seed}_{Guid.NewGuid():N}",
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;
}
/// <summary>
/// 创建测试订单
/// </summary>
private Order CreateTestOrder(AdminBusinessDbContext dbContext, long userId, int seed)
{
var order = new Order
{
OrderNo = $"ORD{DateTime.Now:yyyyMMddHHmmss}{seed % 10000:D4}_{Guid.NewGuid():N}",
UserId = userId,
OrderType = 1,
ProductId = 1,
ProductName = $"测试商品_{seed}",
Amount = 100m,
PayAmount = 100m,
PayType = 1,
Status = 2,
PayTime = DateTime.Now,
CreateTime = DateTime.Now,
UpdateTime = DateTime.Now,
IsDeleted = false
};
dbContext.Orders.Add(order);
dbContext.SaveChanges();
return order;
}
/// <summary>
/// 创建测试测评类型
/// </summary>
private AssessmentType CreateTestAssessmentType(AdminBusinessDbContext dbContext, int seed)
{
var assessmentType = new AssessmentType
{
Name = $"测评类型_{seed}",
Code = $"TYPE_{seed}_{Guid.NewGuid():N}",
Price = 99.00m,
QuestionCount = 80,
Sort = seed,
Status = 1,
CreateTime = DateTime.Now,
UpdateTime = DateTime.Now,
IsDeleted = false
};
dbContext.AssessmentTypes.Add(assessmentType);
dbContext.SaveChanges();
return assessmentType;
}
/// <summary>
/// 创建指定状态的测评记录
/// </summary>
private async Task<AssessmentRecord> CreateTestRecordWithStatus(AdminBusinessDbContext dbContext, int seed, int status)
{
var user = CreateTestUser(dbContext, seed);
var order = CreateTestOrder(dbContext, user.Id, seed);
var assessmentType = CreateTestAssessmentType(dbContext, seed);
var record = new AssessmentRecord
{
UserId = user.Id,
OrderId = order.Id,
AssessmentTypeId = assessmentType.Id,
Name = $"测试人_{seed}",
Phone = $"139{seed % 100000000:D8}",
Gender = 1,
Age = 15,
EducationStage = 2,
Province = "北京市",
City = "北京市",
District = "朝阳区",
Status = status,
StartTime = status >= 2 ? DateTime.Now.AddMinutes(-30) : null,
SubmitTime = status >= 3 ? DateTime.Now.AddMinutes(-10) : null,
CompleteTime = status == 4 ? DateTime.Now : null,
CreateTime = DateTime.Now,
UpdateTime = DateTime.Now,
IsDeleted = false
};
dbContext.AssessmentRecords.Add(record);
await dbContext.SaveChangesAsync();
return record;
}
/// <summary>
/// 批量创建测试记录(用于导出测试)
/// </summary>
private async Task CreateBulkTestRecords(AdminBusinessDbContext dbContext, int count)
{
var user = CreateTestUser(dbContext, 1);
var order = CreateTestOrder(dbContext, user.Id, 1);
var assessmentType = CreateTestAssessmentType(dbContext, 1);
var records = new List<AssessmentRecord>();
for (int i = 0; i < count; i++)
{
records.Add(new AssessmentRecord
{
UserId = user.Id,
OrderId = order.Id,
AssessmentTypeId = assessmentType.Id,
Name = $"测试人_{i}",
Phone = $"139{i % 100000000:D8}",
Gender = (i % 2) + 1,
Age = 10 + (i % 20),
EducationStage = (i % 6) + 1,
Province = "北京市",
City = "北京市",
District = "朝阳区",
Status = (i % 4) + 1,
CreateTime = DateTime.Now.AddMinutes(-i),
UpdateTime = DateTime.Now,
IsDeleted = false
});
}
dbContext.AssessmentRecords.AddRange(records);
await dbContext.SaveChangesAsync();
}
#endregion
}