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#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#region << 版 本 注 释 >>
/*--------------------------------------------------------------------
|* 版权所有 (c) 2026 WenJY 保留所有权利。
|* CLR版本4.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
}