- 系统配置管理模块 (Config) - 内容管理模块 (Banner, Promotion) - 测评管理模块 (Type, Question, Category, Mapping, Conclusion) - 用户管理模块 (User) - 订单管理模块 (Order) - 规划师管理模块 (Planner) - 分销管理模块 (InviteCode, Commission, Withdrawal) - 数据统计仪表盘模块 (Dashboard) - 权限控制集成 - 服务注册配置 全部381个测试通过
690 lines
22 KiB
C#
690 lines
22 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;
|
|
using MiAssessment.Admin.Business.Models.Assessment;
|
|
using MiAssessment.Admin.Business.Models.Common;
|
|
using MiAssessment.Admin.Business.Services;
|
|
using Moq;
|
|
using Xunit;
|
|
|
|
namespace MiAssessment.Tests.Admin;
|
|
|
|
/// <summary>
|
|
/// Category 属性测试
|
|
/// 验证报告分类服务的正确性属性
|
|
/// </summary>
|
|
public class CategoryPropertyTests
|
|
{
|
|
private readonly Mock<ILogger<AssessmentService>> _mockLogger = new();
|
|
|
|
#region Property 9: Tree Structure Correctness
|
|
|
|
/// <summary>
|
|
/// Property 9: 树形结构中所有子分类的 ParentId 必须引用存在的父分类
|
|
/// *For any* category tree query, all child categories SHALL have their ParentId
|
|
/// referencing an existing parent category, and the tree structure SHALL correctly
|
|
/// represent the parent-child relationships.
|
|
///
|
|
/// **Validates: Requirements 6.1, 6.5**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool TreeStructure_AllChildrenHaveValidParentId(PositiveInt seed)
|
|
{
|
|
// Arrange: 创建包含多级分类的数据库
|
|
using var dbContext = CreateDbContext();
|
|
var assessmentTypeId = CreateAssessmentType(dbContext, seed.Get);
|
|
|
|
// 创建顶级分类
|
|
var rootCategory = new ReportCategory
|
|
{
|
|
AssessmentTypeId = assessmentTypeId,
|
|
ParentId = 0,
|
|
Name = $"Root Category {seed.Get}",
|
|
Code = $"ROOT_{seed.Get}",
|
|
CategoryType = 1,
|
|
ScoreRule = 1,
|
|
Sort = 1,
|
|
CreateTime = DateTime.Now,
|
|
UpdateTime = DateTime.Now,
|
|
IsDeleted = false
|
|
};
|
|
dbContext.ReportCategories.Add(rootCategory);
|
|
dbContext.SaveChanges();
|
|
|
|
// 创建子分类
|
|
var childCategory = new ReportCategory
|
|
{
|
|
AssessmentTypeId = assessmentTypeId,
|
|
ParentId = rootCategory.Id,
|
|
Name = $"Child Category {seed.Get}",
|
|
Code = $"CHILD_{seed.Get}",
|
|
CategoryType = 2,
|
|
ScoreRule = 1,
|
|
Sort = 1,
|
|
CreateTime = DateTime.Now,
|
|
UpdateTime = DateTime.Now,
|
|
IsDeleted = false
|
|
};
|
|
dbContext.ReportCategories.Add(childCategory);
|
|
dbContext.SaveChanges();
|
|
|
|
// 创建孙子分类
|
|
var grandchildCategory = new ReportCategory
|
|
{
|
|
AssessmentTypeId = assessmentTypeId,
|
|
ParentId = childCategory.Id,
|
|
Name = $"Grandchild Category {seed.Get}",
|
|
Code = $"GRANDCHILD_{seed.Get}",
|
|
CategoryType = 3,
|
|
ScoreRule = 2,
|
|
Sort = 1,
|
|
CreateTime = DateTime.Now,
|
|
UpdateTime = DateTime.Now,
|
|
IsDeleted = false
|
|
};
|
|
dbContext.ReportCategories.Add(grandchildCategory);
|
|
dbContext.SaveChanges();
|
|
|
|
var service = new AssessmentService(dbContext, _mockLogger.Object);
|
|
|
|
// Act: 获取分类树
|
|
var tree = service.GetCategoryTreeAsync(assessmentTypeId).GetAwaiter().GetResult();
|
|
|
|
// Assert: 验证树形结构正确性
|
|
// 1. 应该有一个顶级分类
|
|
if (tree.Count != 1) return false;
|
|
|
|
var root = tree[0];
|
|
if (root.ParentId != 0) return false;
|
|
if (root.Id != rootCategory.Id) return false;
|
|
|
|
// 2. 顶级分类应该有一个子分类
|
|
if (root.Children.Count != 1) return false;
|
|
|
|
var child = root.Children[0];
|
|
if (child.ParentId != root.Id) return false;
|
|
if (child.Id != childCategory.Id) return false;
|
|
|
|
// 3. 子分类应该有一个孙子分类
|
|
if (child.Children.Count != 1) return false;
|
|
|
|
var grandchild = child.Children[0];
|
|
if (grandchild.ParentId != child.Id) return false;
|
|
if (grandchild.Id != grandchildCategory.Id) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 9: 创建子分类时 ParentId 必须引用存在的父分类
|
|
///
|
|
/// **Validates: Requirements 6.5**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool TreeStructure_CreateChildWithInvalidParentId_ShouldFail(PositiveInt seed)
|
|
{
|
|
// Arrange
|
|
using var dbContext = CreateDbContext();
|
|
var assessmentTypeId = CreateAssessmentType(dbContext, seed.Get);
|
|
var service = new AssessmentService(dbContext, _mockLogger.Object);
|
|
|
|
// Act: 尝试创建引用不存在父分类的子分类
|
|
var request = new CreateCategoryRequest
|
|
{
|
|
AssessmentTypeId = assessmentTypeId,
|
|
ParentId = 999999, // 不存在的父分类ID
|
|
Name = $"Invalid Child {seed.Get}",
|
|
Code = $"INVALID_{seed.Get}",
|
|
CategoryType = 1,
|
|
ScoreRule = 1,
|
|
Sort = 1
|
|
};
|
|
|
|
// Assert: 应该抛出 BusinessException
|
|
try
|
|
{
|
|
service.CreateCategoryAsync(request).GetAwaiter().GetResult();
|
|
return false; // 应该抛出异常
|
|
}
|
|
catch (BusinessException ex)
|
|
{
|
|
return ex.Code == ErrorCodes.CategoryNotFound;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 9: 创建子分类时 ParentId 引用存在的父分类应该成功
|
|
///
|
|
/// **Validates: Requirements 6.5**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool TreeStructure_CreateChildWithValidParentId_ShouldSucceed(PositiveInt seed)
|
|
{
|
|
// Arrange
|
|
using var dbContext = CreateDbContext();
|
|
var assessmentTypeId = CreateAssessmentType(dbContext, seed.Get);
|
|
|
|
// 创建父分类
|
|
var parentCategory = new ReportCategory
|
|
{
|
|
AssessmentTypeId = assessmentTypeId,
|
|
ParentId = 0,
|
|
Name = $"Parent {seed.Get}",
|
|
Code = $"PARENT_{seed.Get}",
|
|
CategoryType = 1,
|
|
ScoreRule = 1,
|
|
Sort = 1,
|
|
CreateTime = DateTime.Now,
|
|
UpdateTime = DateTime.Now,
|
|
IsDeleted = false
|
|
};
|
|
dbContext.ReportCategories.Add(parentCategory);
|
|
dbContext.SaveChanges();
|
|
|
|
var service = new AssessmentService(dbContext, _mockLogger.Object);
|
|
|
|
// Act: 创建引用存在父分类的子分类
|
|
var request = new CreateCategoryRequest
|
|
{
|
|
AssessmentTypeId = assessmentTypeId,
|
|
ParentId = parentCategory.Id,
|
|
Name = $"Child {seed.Get}",
|
|
Code = $"CHILD_{seed.Get}",
|
|
CategoryType = 2,
|
|
ScoreRule = 1,
|
|
Sort = 1
|
|
};
|
|
|
|
try
|
|
{
|
|
var childId = service.CreateCategoryAsync(request).GetAwaiter().GetResult();
|
|
var child = dbContext.ReportCategories.FirstOrDefault(c => c.Id == childId);
|
|
return child != null && child.ParentId == parentCategory.Id;
|
|
}
|
|
catch (BusinessException)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 9: 树形结构应该正确表示多级嵌套关系
|
|
///
|
|
/// **Validates: Requirements 6.1, 6.5**
|
|
/// </summary>
|
|
[Property(MaxTest = 50)]
|
|
public bool TreeStructure_MultiLevelNesting_ShouldBeCorrect(PositiveInt seed, PositiveInt depth)
|
|
{
|
|
// 限制深度为1-5层
|
|
var actualDepth = (depth.Get % 5) + 1;
|
|
|
|
// Arrange
|
|
using var dbContext = CreateDbContext();
|
|
var assessmentTypeId = CreateAssessmentType(dbContext, seed.Get);
|
|
|
|
// 创建多级分类
|
|
var categoryIds = new List<long>();
|
|
long parentId = 0;
|
|
|
|
for (int i = 0; i < actualDepth; i++)
|
|
{
|
|
var category = new ReportCategory
|
|
{
|
|
AssessmentTypeId = assessmentTypeId,
|
|
ParentId = parentId,
|
|
Name = $"Level {i} Category {seed.Get}",
|
|
Code = $"L{i}_{seed.Get}",
|
|
CategoryType = (i % 8) + 1,
|
|
ScoreRule = (i % 2) + 1,
|
|
Sort = i,
|
|
CreateTime = DateTime.Now,
|
|
UpdateTime = DateTime.Now,
|
|
IsDeleted = false
|
|
};
|
|
dbContext.ReportCategories.Add(category);
|
|
dbContext.SaveChanges();
|
|
categoryIds.Add(category.Id);
|
|
parentId = category.Id;
|
|
}
|
|
|
|
var service = new AssessmentService(dbContext, _mockLogger.Object);
|
|
|
|
// Act: 获取分类树
|
|
var tree = service.GetCategoryTreeAsync(assessmentTypeId).GetAwaiter().GetResult();
|
|
|
|
// Assert: 验证树形结构深度正确
|
|
var currentLevel = tree;
|
|
for (int i = 0; i < actualDepth; i++)
|
|
{
|
|
if (currentLevel.Count != 1) return false;
|
|
var node = currentLevel[0];
|
|
if (node.Id != categoryIds[i]) return false;
|
|
|
|
if (i < actualDepth - 1)
|
|
{
|
|
currentLevel = node.Children;
|
|
}
|
|
else
|
|
{
|
|
// 最后一级应该没有子分类
|
|
if (node.Children.Count != 0) return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 9: 软删除的分类不应出现在树形结构中
|
|
///
|
|
/// **Validates: Requirements 6.1**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool TreeStructure_DeletedCategoriesNotInTree(PositiveInt seed)
|
|
{
|
|
// Arrange
|
|
using var dbContext = CreateDbContext();
|
|
var assessmentTypeId = CreateAssessmentType(dbContext, seed.Get);
|
|
|
|
// 创建两个分类,一个正常,一个已删除
|
|
var normalCategory = new ReportCategory
|
|
{
|
|
AssessmentTypeId = assessmentTypeId,
|
|
ParentId = 0,
|
|
Name = $"Normal {seed.Get}",
|
|
Code = $"NORMAL_{seed.Get}",
|
|
CategoryType = 1,
|
|
ScoreRule = 1,
|
|
Sort = 1,
|
|
CreateTime = DateTime.Now,
|
|
UpdateTime = DateTime.Now,
|
|
IsDeleted = false
|
|
};
|
|
|
|
var deletedCategory = new ReportCategory
|
|
{
|
|
AssessmentTypeId = assessmentTypeId,
|
|
ParentId = 0,
|
|
Name = $"Deleted {seed.Get}",
|
|
Code = $"DELETED_{seed.Get}",
|
|
CategoryType = 2,
|
|
ScoreRule = 1,
|
|
Sort = 2,
|
|
CreateTime = DateTime.Now,
|
|
UpdateTime = DateTime.Now,
|
|
IsDeleted = true // 已软删除
|
|
};
|
|
|
|
dbContext.ReportCategories.AddRange(normalCategory, deletedCategory);
|
|
dbContext.SaveChanges();
|
|
|
|
var service = new AssessmentService(dbContext, _mockLogger.Object);
|
|
|
|
// Act: 获取分类树
|
|
var tree = service.GetCategoryTreeAsync(assessmentTypeId).GetAwaiter().GetResult();
|
|
|
|
// Assert: 只应该有一个分类(正常的那个)
|
|
return tree.Count == 1 && tree[0].Id == normalCategory.Id;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Property 18: Category Deletion Constraint
|
|
|
|
/// <summary>
|
|
/// Property 18: 有子分类的分类不能删除
|
|
/// *For any* category with child categories, attempting to delete the category
|
|
/// SHALL return an error and the category SHALL remain unchanged.
|
|
///
|
|
/// **Validates: Requirements 6.6**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool DeletionConstraint_CategoryWithChildren_ShouldFailToDelete(PositiveInt seed)
|
|
{
|
|
// Arrange: 创建父子分类
|
|
using var dbContext = CreateDbContext();
|
|
var assessmentTypeId = CreateAssessmentType(dbContext, seed.Get);
|
|
|
|
var parentCategory = new ReportCategory
|
|
{
|
|
AssessmentTypeId = assessmentTypeId,
|
|
ParentId = 0,
|
|
Name = $"Parent {seed.Get}",
|
|
Code = $"PARENT_{seed.Get}",
|
|
CategoryType = 1,
|
|
ScoreRule = 1,
|
|
Sort = 1,
|
|
CreateTime = DateTime.Now,
|
|
UpdateTime = DateTime.Now,
|
|
IsDeleted = false
|
|
};
|
|
dbContext.ReportCategories.Add(parentCategory);
|
|
dbContext.SaveChanges();
|
|
|
|
var childCategory = new ReportCategory
|
|
{
|
|
AssessmentTypeId = assessmentTypeId,
|
|
ParentId = parentCategory.Id,
|
|
Name = $"Child {seed.Get}",
|
|
Code = $"CHILD_{seed.Get}",
|
|
CategoryType = 2,
|
|
ScoreRule = 1,
|
|
Sort = 1,
|
|
CreateTime = DateTime.Now,
|
|
UpdateTime = DateTime.Now,
|
|
IsDeleted = false
|
|
};
|
|
dbContext.ReportCategories.Add(childCategory);
|
|
dbContext.SaveChanges();
|
|
|
|
var service = new AssessmentService(dbContext, _mockLogger.Object);
|
|
|
|
// Act: 尝试删除有子分类的父分类
|
|
try
|
|
{
|
|
service.DeleteCategoryAsync(parentCategory.Id).GetAwaiter().GetResult();
|
|
return false; // 应该抛出异常
|
|
}
|
|
catch (BusinessException ex)
|
|
{
|
|
// Assert: 应该返回 CategoryHasChildren 错误
|
|
if (ex.Code != ErrorCodes.CategoryHasChildren) return false;
|
|
|
|
// 验证父分类未被删除
|
|
var parent = dbContext.ReportCategories.FirstOrDefault(c => c.Id == parentCategory.Id);
|
|
return parent != null && !parent.IsDeleted;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 18: 没有子分类的分类可以删除
|
|
///
|
|
/// **Validates: Requirements 6.6**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool DeletionConstraint_CategoryWithoutChildren_ShouldSucceedToDelete(PositiveInt seed)
|
|
{
|
|
// Arrange: 创建没有子分类的分类
|
|
using var dbContext = CreateDbContext();
|
|
var assessmentTypeId = CreateAssessmentType(dbContext, seed.Get);
|
|
|
|
var category = new ReportCategory
|
|
{
|
|
AssessmentTypeId = assessmentTypeId,
|
|
ParentId = 0,
|
|
Name = $"Leaf {seed.Get}",
|
|
Code = $"LEAF_{seed.Get}",
|
|
CategoryType = 1,
|
|
ScoreRule = 1,
|
|
Sort = 1,
|
|
CreateTime = DateTime.Now,
|
|
UpdateTime = DateTime.Now,
|
|
IsDeleted = false
|
|
};
|
|
dbContext.ReportCategories.Add(category);
|
|
dbContext.SaveChanges();
|
|
|
|
var service = new AssessmentService(dbContext, _mockLogger.Object);
|
|
|
|
// Act: 删除没有子分类的分类
|
|
try
|
|
{
|
|
var result = service.DeleteCategoryAsync(category.Id).GetAwaiter().GetResult();
|
|
|
|
// Assert: 应该删除成功(软删除)
|
|
var deletedCategory = dbContext.ReportCategories.FirstOrDefault(c => c.Id == category.Id);
|
|
return result && deletedCategory != null && deletedCategory.IsDeleted;
|
|
}
|
|
catch (BusinessException)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 18: 删除子分类后,父分类可以被删除
|
|
///
|
|
/// **Validates: Requirements 6.6**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool DeletionConstraint_AfterChildDeleted_ParentCanBeDeleted(PositiveInt seed)
|
|
{
|
|
// Arrange: 创建父子分类
|
|
using var dbContext = CreateDbContext();
|
|
var assessmentTypeId = CreateAssessmentType(dbContext, seed.Get);
|
|
|
|
var parentCategory = new ReportCategory
|
|
{
|
|
AssessmentTypeId = assessmentTypeId,
|
|
ParentId = 0,
|
|
Name = $"Parent {seed.Get}",
|
|
Code = $"PARENT_{seed.Get}",
|
|
CategoryType = 1,
|
|
ScoreRule = 1,
|
|
Sort = 1,
|
|
CreateTime = DateTime.Now,
|
|
UpdateTime = DateTime.Now,
|
|
IsDeleted = false
|
|
};
|
|
dbContext.ReportCategories.Add(parentCategory);
|
|
dbContext.SaveChanges();
|
|
|
|
var childCategory = new ReportCategory
|
|
{
|
|
AssessmentTypeId = assessmentTypeId,
|
|
ParentId = parentCategory.Id,
|
|
Name = $"Child {seed.Get}",
|
|
Code = $"CHILD_{seed.Get}",
|
|
CategoryType = 2,
|
|
ScoreRule = 1,
|
|
Sort = 1,
|
|
CreateTime = DateTime.Now,
|
|
UpdateTime = DateTime.Now,
|
|
IsDeleted = false
|
|
};
|
|
dbContext.ReportCategories.Add(childCategory);
|
|
dbContext.SaveChanges();
|
|
|
|
var service = new AssessmentService(dbContext, _mockLogger.Object);
|
|
|
|
// Act: 先删除子分类
|
|
try
|
|
{
|
|
service.DeleteCategoryAsync(childCategory.Id).GetAwaiter().GetResult();
|
|
}
|
|
catch (BusinessException)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// 然后删除父分类
|
|
try
|
|
{
|
|
var result = service.DeleteCategoryAsync(parentCategory.Id).GetAwaiter().GetResult();
|
|
|
|
// Assert: 父分类应该被成功删除
|
|
var parent = dbContext.ReportCategories.FirstOrDefault(c => c.Id == parentCategory.Id);
|
|
return result && parent != null && parent.IsDeleted;
|
|
}
|
|
catch (BusinessException)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 18: 有多个子分类的分类不能删除
|
|
///
|
|
/// **Validates: Requirements 6.6**
|
|
/// </summary>
|
|
[Property(MaxTest = 50)]
|
|
public bool DeletionConstraint_CategoryWithMultipleChildren_ShouldFailToDelete(PositiveInt seed, PositiveInt childCount)
|
|
{
|
|
// 限制子分类数量为1-5
|
|
var actualChildCount = (childCount.Get % 5) + 1;
|
|
|
|
// Arrange: 创建父分类和多个子分类
|
|
using var dbContext = CreateDbContext();
|
|
var assessmentTypeId = CreateAssessmentType(dbContext, seed.Get);
|
|
|
|
var parentCategory = new ReportCategory
|
|
{
|
|
AssessmentTypeId = assessmentTypeId,
|
|
ParentId = 0,
|
|
Name = $"Parent {seed.Get}",
|
|
Code = $"PARENT_{seed.Get}",
|
|
CategoryType = 1,
|
|
ScoreRule = 1,
|
|
Sort = 1,
|
|
CreateTime = DateTime.Now,
|
|
UpdateTime = DateTime.Now,
|
|
IsDeleted = false
|
|
};
|
|
dbContext.ReportCategories.Add(parentCategory);
|
|
dbContext.SaveChanges();
|
|
|
|
// 创建多个子分类
|
|
for (int i = 0; i < actualChildCount; i++)
|
|
{
|
|
var childCategory = new ReportCategory
|
|
{
|
|
AssessmentTypeId = assessmentTypeId,
|
|
ParentId = parentCategory.Id,
|
|
Name = $"Child {i} {seed.Get}",
|
|
Code = $"CHILD_{i}_{seed.Get}",
|
|
CategoryType = (i % 8) + 1,
|
|
ScoreRule = 1,
|
|
Sort = i,
|
|
CreateTime = DateTime.Now,
|
|
UpdateTime = DateTime.Now,
|
|
IsDeleted = false
|
|
};
|
|
dbContext.ReportCategories.Add(childCategory);
|
|
}
|
|
dbContext.SaveChanges();
|
|
|
|
var service = new AssessmentService(dbContext, _mockLogger.Object);
|
|
|
|
// Act: 尝试删除有多个子分类的父分类
|
|
try
|
|
{
|
|
service.DeleteCategoryAsync(parentCategory.Id).GetAwaiter().GetResult();
|
|
return false; // 应该抛出异常
|
|
}
|
|
catch (BusinessException ex)
|
|
{
|
|
// Assert: 应该返回 CategoryHasChildren 错误
|
|
if (ex.Code != ErrorCodes.CategoryHasChildren) return false;
|
|
|
|
// 验证父分类未被删除
|
|
var parent = dbContext.ReportCategories.FirstOrDefault(c => c.Id == parentCategory.Id);
|
|
return parent != null && !parent.IsDeleted;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 18: 软删除的子分类不应阻止父分类删除
|
|
///
|
|
/// **Validates: Requirements 6.6**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public bool DeletionConstraint_SoftDeletedChildrenDontBlockParentDeletion(PositiveInt seed)
|
|
{
|
|
// Arrange: 创建父分类和已软删除的子分类
|
|
using var dbContext = CreateDbContext();
|
|
var assessmentTypeId = CreateAssessmentType(dbContext, seed.Get);
|
|
|
|
var parentCategory = new ReportCategory
|
|
{
|
|
AssessmentTypeId = assessmentTypeId,
|
|
ParentId = 0,
|
|
Name = $"Parent {seed.Get}",
|
|
Code = $"PARENT_{seed.Get}",
|
|
CategoryType = 1,
|
|
ScoreRule = 1,
|
|
Sort = 1,
|
|
CreateTime = DateTime.Now,
|
|
UpdateTime = DateTime.Now,
|
|
IsDeleted = false
|
|
};
|
|
dbContext.ReportCategories.Add(parentCategory);
|
|
dbContext.SaveChanges();
|
|
|
|
var softDeletedChild = new ReportCategory
|
|
{
|
|
AssessmentTypeId = assessmentTypeId,
|
|
ParentId = parentCategory.Id,
|
|
Name = $"Deleted Child {seed.Get}",
|
|
Code = $"DELETED_CHILD_{seed.Get}",
|
|
CategoryType = 2,
|
|
ScoreRule = 1,
|
|
Sort = 1,
|
|
CreateTime = DateTime.Now,
|
|
UpdateTime = DateTime.Now,
|
|
IsDeleted = true // 已软删除
|
|
};
|
|
dbContext.ReportCategories.Add(softDeletedChild);
|
|
dbContext.SaveChanges();
|
|
|
|
var service = new AssessmentService(dbContext, _mockLogger.Object);
|
|
|
|
// Act: 删除父分类(子分类已软删除,不应阻止)
|
|
try
|
|
{
|
|
var result = service.DeleteCategoryAsync(parentCategory.Id).GetAwaiter().GetResult();
|
|
|
|
// Assert: 父分类应该被成功删除
|
|
var parent = dbContext.ReportCategories.FirstOrDefault(c => c.Id == parentCategory.Id);
|
|
return result && parent != null && parent.IsDeleted;
|
|
}
|
|
catch (BusinessException)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 辅助方法
|
|
|
|
/// <summary>
|
|
/// 创建内存数据库上下文
|
|
/// </summary>
|
|
private AdminBusinessDbContext CreateDbContext()
|
|
{
|
|
var options = new DbContextOptionsBuilder<AdminBusinessDbContext>()
|
|
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
|
|
.Options;
|
|
|
|
return new AdminBusinessDbContext(options);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 创建测评类型并返回ID
|
|
/// </summary>
|
|
private long CreateAssessmentType(AdminBusinessDbContext dbContext, int seed)
|
|
{
|
|
var assessmentType = new AssessmentType
|
|
{
|
|
Name = $"Test Assessment {seed}",
|
|
Code = $"TEST_{seed}_{Guid.NewGuid():N}".Substring(0, 20),
|
|
Price = 99.99m,
|
|
QuestionCount = 80,
|
|
Sort = 1,
|
|
Status = 1,
|
|
CreateTime = DateTime.Now,
|
|
UpdateTime = DateTime.Now,
|
|
IsDeleted = false
|
|
};
|
|
dbContext.AssessmentTypes.Add(assessmentType);
|
|
dbContext.SaveChanges();
|
|
return assessmentType.Id;
|
|
}
|
|
|
|
#endregion
|
|
}
|