You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

516 lines
15 KiB
C#

#region << 版 本 注 释 >>
/*--------------------------------------------------------------------
|* (c) 2026 WenJY
|* CLR4.0.30319.42000
|* Mr.Wen's MacBook Pro
|* Sln.Wcs.Business.Tests
|*
|*
|* WenJY
|*
|* 2026-05-17
|* V1.0.0
|* StoreTaskBusiness
|*
|*--------------------------------------------------------------------
|*
|*
|*
|*
|* V1.0.0
|*--------------------------------------------------------------------*/
#endregion << 版 本 注 释 >>
using Moq;
using Sln.Wcs.Business.Domain.Dto.CreateTask;
using Sln.Wcs.Business.Domain.Dto.FilterLocation;
using Sln.Wcs.Business.Domain.Dto.SaveTask;
using Sln.Wcs.Business.Domain.Enum;
using Sln.Wcs.Model.Domain;
using Sln.Wcs.Repository.service;
using Xunit;
namespace Sln.Wcs.Business.Tests;
/// <summary>
/// 可测试的 StoreTaskBusiness 子类,用于访问 protected 方法
/// </summary>
public class TestableStoreTaskBusiness : StoreTaskBusiness
{
public TestableStoreTaskBusiness(
IBasePathInfoService basePathInfoService,
ILiveTaskQueueService liveTaskQueueService,
IBaseStoreInfoService baseStoreInfoService)
: base(basePathInfoService, liveTaskQueueService, baseStoreInfoService)
{
}
public void PublicValidateCreateTaskParams(CreateTaskDto dto) =>
ValidateCreateTaskParams(dto);
public void PublicValidateFilterLocationParams(FilterLocationDto dto) =>
ValidateFilterLocationParams(dto);
public string PublicGenerateTaskCode() => GenerateTaskCode();
public string PublicGetCategoryName(TaskCategoryEnum category) =>
GetCategoryName(category);
public string PublicGetTaskTypeName(TaskTypeEnum taskType) =>
GetTaskTypeName(taskType);
public string PublicGetTaskSuccessMessage(
string taskCode, string pathName, TaskTypeEnum taskType, TaskCategoryEnum taskCategory) =>
GetTaskSuccessMessage(taskCode, pathName, taskType, taskCategory);
public BasePathInfo PublicGetPathInfo(
CreateTaskDto createTaskDto, TaskTypeEnum taskType, TaskCategoryEnum taskCategory) =>
GetPathInfo(createTaskDto, taskType, taskCategory);
}
public class StoreTaskBusinessTests
{
private readonly Mock<IBasePathInfoService> _mockBasePathInfoService;
private readonly Mock<ILiveTaskQueueService> _mockLiveTaskQueueService;
private readonly Mock<IBaseStoreInfoService> _mockBaseStoreInfoService;
private readonly TestableStoreTaskBusiness _storeTaskBusiness;
public StoreTaskBusinessTests()
{
_mockBasePathInfoService = new Mock<IBasePathInfoService>();
_mockLiveTaskQueueService = new Mock<ILiveTaskQueueService>();
_mockBaseStoreInfoService = new Mock<IBaseStoreInfoService>();
_storeTaskBusiness = new TestableStoreTaskBusiness(
_mockBasePathInfoService.Object,
_mockLiveTaskQueueService.Object,
_mockBaseStoreInfoService.Object);
}
#region GetCategoryName 测试
[Theory]
[InlineData(TaskCategoryEnum.Material, "包材")]
[InlineData(TaskCategoryEnum.Product, "成品")]
[InlineData(TaskCategoryEnum.Pallet, "托盘")]
public void GetCategoryName_ValidCategory_ReturnsCorrectName(TaskCategoryEnum category, string expected)
{
var result = _storeTaskBusiness.PublicGetCategoryName(category);
Assert.Equal(expected, result);
}
#endregion
#region GetTaskTypeName 测试
[Theory]
[InlineData(TaskTypeEnum.InStore, "入库")]
[InlineData(TaskTypeEnum.OutStore, "出库")]
public void GetTaskTypeName_ValidType_ReturnsCorrectName(TaskTypeEnum taskType, string expected)
{
var result = _storeTaskBusiness.PublicGetTaskTypeName(taskType);
Assert.Equal(expected, result);
}
#endregion
#region ValidateCreateTaskParams 测试
[Fact]
public void ValidateCreateTaskParams_NullMaterialCode_ThrowsException()
{
var dto = new CreateTaskDto
{
materialCode = null!,
palletBarcode = "PLT001",
startPoint = "A",
endPoint = "B"
};
var exception = Assert.Throws<InvalidOperationException>(() =>
_storeTaskBusiness.PublicValidateCreateTaskParams(dto));
Assert.Contains("物料编号不允许为 NULL", exception.Message);
}
[Fact]
public void ValidateCreateTaskParams_NullPalletBarcode_ThrowsException()
{
var dto = new CreateTaskDto
{
materialCode = "MAT001",
palletBarcode = null!,
startPoint = "A",
endPoint = "B",
taskCategory = TaskCategoryEnum.Material
};
var exception = Assert.Throws<InvalidOperationException>(() =>
_storeTaskBusiness.PublicValidateCreateTaskParams(dto));
Assert.Contains("条码不允许为 NULL", exception.Message);
}
[Fact]
public void ValidateCreateTaskParams_NullStartPoint_ThrowsException()
{
var dto = new CreateTaskDto
{
materialCode = "MAT001",
palletBarcode = "PLT001",
startPoint = null!,
endPoint = "B"
};
var exception = Assert.Throws<InvalidOperationException>(() =>
_storeTaskBusiness.PublicValidateCreateTaskParams(dto));
Assert.Contains("起始位置、终点位置不允许为 NULL", exception.Message);
}
[Fact]
public void ValidateCreateTaskParams_EmptyEndPoint_ThrowsException()
{
var dto = new CreateTaskDto
{
materialCode = "MAT001",
palletBarcode = "PLT001",
startPoint = "A",
endPoint = ""
};
var exception = Assert.Throws<InvalidOperationException>(() =>
_storeTaskBusiness.PublicValidateCreateTaskParams(dto));
Assert.Contains("起始位置、终点位置不允许为 NULL", exception.Message);
}
[Fact]
public void ValidateCreateTaskParams_ValidParams_NoException()
{
var dto = new CreateTaskDto
{
materialCode = "MAT001",
palletBarcode = "PLT001",
startPoint = "A",
endPoint = "B",
taskCategory = TaskCategoryEnum.Material
};
var exception = Record.Exception(() =>
_storeTaskBusiness.PublicValidateCreateTaskParams(dto));
Assert.Null(exception);
}
#endregion
#region ValidateFilterLocationParams 测试
[Fact]
public void ValidateFilterLocationParams_NullMaterialCode_ThrowsException()
{
var dto = new FilterLocationDto
{
materialCode = null!
};
var exception = Assert.Throws<InvalidOperationException>(() =>
_storeTaskBusiness.PublicValidateFilterLocationParams(dto));
Assert.Contains("物料编号不允许为 NULL", exception.Message);
}
[Fact]
public void ValidateFilterLocationParams_ValidParams_NoException()
{
var dto = new FilterLocationDto
{
materialCode = "MAT001"
};
var exception = Record.Exception(() =>
_storeTaskBusiness.PublicValidateFilterLocationParams(dto));
Assert.Null(exception);
}
#endregion
#region GenerateTaskCode 测试
[Fact]
public void GenerateTaskCode_ReturnsCorrectFormat()
{
var taskCode = _storeTaskBusiness.PublicGenerateTaskCode();
Assert.NotNull(taskCode);
Assert.Equal(18, taskCode.Length);
Assert.True(long.TryParse(taskCode[..14], out _));
Assert.True(int.TryParse(taskCode[14..], out var randomPart));
Assert.InRange(randomPart, 1000, 9999);
}
[Fact]
public void GenerateTaskCode_MultipleCalls_GeneratesUniqueCodes()
{
var codes = new HashSet<string>();
for (int i = 0; i < 100; i++)
{
codes.Add(_storeTaskBusiness.PublicGenerateTaskCode());
}
Assert.Equal(100, codes.Count);
}
#endregion
#region CreateTask 测试
[Fact]
public void CreateTask_ValidInput_ReturnsSuccessResult()
{
var dto = new CreateTaskDto
{
materialCode = "MAT001",
materialBarcode = "MAT001BAR",
palletBarcode = "PLT001",
amount = 100,
startPoint = "START",
endPoint = "END",
taskType = TaskTypeEnum.InStore,
taskCategory = TaskCategoryEnum.Material
};
var pathDetails = new List<BasePathDetails>
{
new BasePathDetails
{
objId = 1,
pathCode = "PATH1",
startPoint = "START",
endPoint = "MID",
deviceType = 0
},
new BasePathDetails
{
objId = 2,
pathCode = "PATH2",
startPoint = "MID",
endPoint = "END",
deviceType = 0
}
};
var pathInfo = new BasePathInfo
{
objId = 1,
pathCode = "MAIN_PATH",
pathName = "主输送线",
pathType = 1,
pathCategory = 1,
startPoint = "START",
endPoint = "END",
pathDetails = pathDetails
};
_mockBasePathInfoService
.Setup(x => x.GetBasePathInfo(It.IsAny<System.Linq.Expressions.Expression<Func<BasePathInfo, bool>>>()))
.Returns(new List<BasePathInfo> { pathInfo });
var result = _storeTaskBusiness.CreateTask(dto);
Assert.Equal(BusinessStatusEnum., result.code);
Assert.NotNull(result.data);
Assert.NotNull(result.data.taskCode);
Assert.Equal(2, result.data.taskDetails.Count);
Assert.Equal(2, result.data.taskQueue.taskSteps);
}
[Fact]
public void CreateTask_PathNotFound_ReturnsErrorResult()
{
var dto = new CreateTaskDto
{
materialCode = "MAT001",
palletBarcode = "PLT001",
startPoint = "INVALID",
endPoint = "INVALID",
taskType = TaskTypeEnum.InStore,
taskCategory = TaskCategoryEnum.Material
};
_mockBasePathInfoService
.Setup(x => x.GetBasePathInfo(It.IsAny<System.Linq.Expressions.Expression<Func<BasePathInfo, bool>>>()))
.Returns(new List<BasePathInfo>());
var result = _storeTaskBusiness.CreateTask(dto);
Assert.Equal(BusinessStatusEnum., result.code);
Assert.Contains("输送路径为 NULL", result.msg);
}
#endregion
#region FilterLocation 测试
[Fact]
public void FilterLocation_ValidInput_ReturnsSuccessResult()
{
var dto = new FilterLocationDto
{
materialCode = "MAT001",
taskType = TaskTypeEnum.InStore,
taskCategory = TaskCategoryEnum.Material
};
var locationInfos = new List<BaseLocationInfo>
{
new BaseLocationInfo
{
locationCode = "LOC001",
locationRows = 1,
locationColumns = 1,
locationLayers = 1,
locationStatus = 0,
materialCode = "MAT001",
isFlag = 1
}
};
var storeInfo = new BaseStoreInfo
{
storeCode = "STORE001",
storeName = "测试仓库",
storeType = 1,
isFlag = 1,
locationInfos = locationInfos
};
_mockBaseStoreInfoService
.Setup(x => x.GetBasePathInfo(
It.IsAny<System.Linq.Expressions.Expression<Func<BaseStoreInfo, bool>>>(),
It.IsAny<System.Linq.Expressions.Expression<Func<BaseLocationInfo, bool>>>()))
.Returns(new List<BaseStoreInfo> { storeInfo });
var result = _storeTaskBusiness.FilterLocation(dto);
Assert.Equal(BusinessStatusEnum., result.code);
Assert.NotNull(result.data);
Assert.NotNull(result.data.storeInfo);
Assert.NotNull(result.data.locationInfo);
Assert.Single(result.data.locationInfos);
}
[Fact]
public void FilterLocation_NoAvailableStore_ReturnsErrorResult()
{
var dto = new FilterLocationDto
{
materialCode = "MAT001",
taskType = TaskTypeEnum.InStore,
taskCategory = TaskCategoryEnum.Material
};
_mockBaseStoreInfoService
.Setup(x => x.GetBasePathInfo(
It.IsAny<System.Linq.Expressions.Expression<Func<BaseStoreInfo, bool>>>(),
It.IsAny<System.Linq.Expressions.Expression<Func<BaseLocationInfo, bool>>>()))
.Returns(new List<BaseStoreInfo>());
var result = _storeTaskBusiness.FilterLocation(dto);
Assert.Equal(BusinessStatusEnum., result.code);
Assert.Contains("未获取到可用仓库", result.msg);
}
#endregion
#region SaveTask 测试
[Fact]
public void SaveTask_ValidInput_ReturnsSuccessResult()
{
var dto = new SaveTaskDto
{
taskQueue = new LiveTaskQueue
{
taskCode = "TASK001",
materialCode = "MAT001",
palletBarcode = "PLT001",
startPoint = "A",
endPoint = "B",
taskType = 1,
taskCategory = 1
}
};
_mockLiveTaskQueueService
.Setup(x => x.InsertTaskQueue(It.IsAny<LiveTaskQueue>()))
.Returns(true);
var result = _storeTaskBusiness.SaveTask(dto);
Assert.Equal(BusinessStatusEnum., result.code);
Assert.NotNull(result.data);
Assert.True(result.data.isRes);
}
[Fact]
public void SaveTask_InsertFails_ReturnsFalse()
{
var dto = new SaveTaskDto
{
taskQueue = new LiveTaskQueue
{
taskCode = "TASK001",
materialCode = "MAT001",
palletBarcode = "PLT001",
startPoint = "A",
endPoint = "B",
taskType = 1,
taskCategory = 1
}
};
_mockLiveTaskQueueService
.Setup(x => x.InsertTaskQueue(It.IsAny<LiveTaskQueue>()))
.Returns(false);
var result = _storeTaskBusiness.SaveTask(dto);
Assert.Equal(BusinessStatusEnum., result.code);
Assert.NotNull(result.data);
Assert.False(result.data.isRes);
}
#endregion
#region GetTaskSuccessMessage 测试
[Fact]
public void GetTaskSuccessMessage_ReturnsCorrectMessage()
{
var message = _storeTaskBusiness.PublicGetTaskSuccessMessage(
"TASK001",
"主输送线",
TaskTypeEnum.InStore,
TaskCategoryEnum.Material);
Assert.Equal("包材入库任务创建成功:TASK001;关联路径:主输送线", message);
}
[Fact]
public void GetTaskSuccessMessage_ProductOutStore_ReturnsCorrectMessage()
{
var message = _storeTaskBusiness.PublicGetTaskSuccessMessage(
"TASK002",
"成品出库线",
TaskTypeEnum.OutStore,
TaskCategoryEnum.Product);
Assert.Equal("成品出库任务创建成功:TASK002;关联路径:成品出库线", message);
}
#endregion
}