This commit is contained in:
2026-04-06 22:38:23 +08:00
parent 71e099ca8e
commit d554e9e659
10 changed files with 1225 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.0.4" />
<PackageReference Include="MSTest.TestFramework" Version="3.0.4" />
<PackageReference Include="Moq" Version="4.20.69" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OrpaonVision.Core\OrpaonVision.Core.csproj" />
<ProjectReference Include="..\OrpaonVision.Model\OrpaonVision.Model.csproj" />
<ProjectReference Include="..\OrpaonVision.SiteApp\OrpaonVision.SiteApp.csproj" />
<ProjectReference Include="..\OrpaonVision.ConfigApp\OrpaonVision.ConfigApp.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,128 @@
using Microsoft.Extensions.Logging;
using Moq;
using OrpaonVision.Core.Results;
using OrpaonVision.SiteApp.Runtime.Contracts;
using OrpaonVision.SiteApp.Runtime.Services;
namespace OrpaonVision.SiteApp.Tests.Runtime.Services;
/// <summary>
/// 运行时状态机服务单元测试。
/// </summary>
[TestClass]
public class RuntimeStateMachineServiceTests
{
private IRuntimeStateMachineService _stateMachine = null!;
private Mock<ILogger<IRuntimeStateMachineService>> _loggerMock = null!;
[TestInitialize]
public void TestInitialize()
{
_loggerMock = new Mock<ILogger<IRuntimeStateMachineService>>();
// 使用简单状态机实现进行测试
_stateMachine = new SimpleRuntimeStateMachineService(_loggerMock.Object);
}
[TestMethod]
public void GetSnapshot_InitialState_ReturnsCorrectSnapshot()
{
// Act
var snapshot = _stateMachine.GetSnapshot();
// Assert
Assert.IsNotNull(snapshot);
Assert.AreEqual(0, snapshot.CurrentLayer);
Assert.AreEqual(0, snapshot.TotalLayers);
Assert.IsTrue(snapshot.StateText.Contains("Idle") || snapshot.StateText.Contains("初始"));
}
[TestMethod]
public void MoveToNextLayer_FromInitialState_ReturnsSuccess()
{
// Act
var result = _stateMachine.MoveToNextLayer();
// Assert
Assert.IsTrue(result.Succeeded);
var snapshot = _stateMachine.GetSnapshot();
Assert.AreEqual(1, snapshot.CurrentLayer);
}
[TestMethod]
public void MoveToNextLayer_SequentialCalls_ReturnsSuccess()
{
// Act & Assert - 第一层
var result1 = _stateMachine.MoveToNextLayer();
Assert.IsTrue(result1.Succeeded);
var snapshot1 = _stateMachine.GetSnapshot();
Assert.AreEqual(1, snapshot1.CurrentLayer);
// Act & Assert - 第二层
var result2 = _stateMachine.MoveToNextLayer();
Assert.IsTrue(result2.Succeeded);
var snapshot2 = _stateMachine.GetSnapshot();
Assert.AreEqual(2, snapshot2.CurrentLayer);
}
[TestMethod]
public void Reset_AfterProgress_ReturnsToInitialState()
{
// Arrange - 推进几层
_stateMachine.MoveToNextLayer();
_stateMachine.MoveToNextLayer();
var snapshotBefore = _stateMachine.GetSnapshot();
Assert.AreEqual(2, snapshotBefore.CurrentLayer);
// Act
_stateMachine.Reset();
// Assert
var snapshotAfter = _stateMachine.GetSnapshot();
Assert.AreEqual(0, snapshotAfter.CurrentLayer);
Assert.AreEqual(0, snapshotAfter.TotalLayers);
}
[TestMethod]
public void StateTransitionFlow_CompleteWorkflow_ReturnsExpectedStates()
{
// Arrange & Act - 初始状态
var initialSnapshot = _stateMachine.GetSnapshot();
Assert.AreEqual(0, initialSnapshot.CurrentLayer);
// Act & Assert - 第一层
var result1 = _stateMachine.MoveToNextLayer();
Assert.IsTrue(result1.Succeeded);
var snapshot1 = _stateMachine.GetSnapshot();
Assert.AreEqual(1, snapshot1.CurrentLayer);
// Act & Assert - 第二层
var result2 = _stateMachine.MoveToNextLayer();
Assert.IsTrue(result2.Succeeded);
var snapshot2 = _stateMachine.GetSnapshot();
Assert.AreEqual(2, snapshot2.CurrentLayer);
// Act & Assert - 重置
_stateMachine.Reset();
var finalSnapshot = _stateMachine.GetSnapshot();
Assert.AreEqual(0, finalSnapshot.CurrentLayer);
}
[TestMethod]
public void GetSnapshot_AfterMultipleTransitions_ReturnsCorrectCurrentState()
{
// Arrange
for (int i = 0; i < 5; i++)
{
_stateMachine.MoveToNextLayer();
}
// Act
var snapshot = _stateMachine.GetSnapshot();
// Assert
Assert.AreEqual(5, snapshot.CurrentLayer);
Assert.IsNotNull(snapshot.StateText);
Assert.IsFalse(string.IsNullOrEmpty(snapshot.StateText));
}
}

View File

@@ -0,0 +1,238 @@
using Microsoft.Extensions.Logging;
using Moq;
using OrpaonVision.Core.Results;
using OrpaonVision.Core.Training;
using OrpaonVision.Core.Training.Contracts;
using OrpaonVision.Core.Training.Contracts.Commands;
namespace OrpaonVision.SiteApp.Tests.Training;
/// <summary>
/// 模型包导入激活单元测试。
/// </summary>
[TestClass]
public class ModelPackageImportActivationTests
{
private Mock<IModelPackageAppService> _modelPackageServiceMock = null!;
private Mock<ILogger<IModelPackageAppService>> _loggerMock = null!;
[TestInitialize]
public void TestInitialize()
{
_modelPackageServiceMock = new Mock<IModelPackageAppService>();
_loggerMock = new Mock<ILogger<IModelPackageAppService>>();
}
[TestMethod]
public async Task ImportPackageAsync_ValidPackage_ReturnsSuccess()
{
// Arrange
var packagePath = "test_package.ovpkg";
var expectedResult = new ModelPackageImportResultDto
{
ModelPackageId = Guid.NewGuid(),
Status = ModelPackageImportStatus.Imported,
Message = "导入成功",
ImportedAtUtc = DateTime.UtcNow,
ImportedBy = "TestUser"
};
_modelPackageServiceMock
.Setup(x => x.ImportPackageAsync(packagePath, It.IsAny<CancellationToken>()))
.ReturnsAsync(Result<ModelPackageImportResultDto>.Success(expectedResult));
// Act
var result = await _modelPackageServiceMock.Object.ImportPackageAsync(packagePath);
// Assert
Assert.IsTrue(result.Succeeded);
Assert.IsNotNull(result.Data);
Assert.AreEqual(ModelPackageImportStatus.Imported, result.Data.Status);
Assert.AreEqual("导入成功", result.Data.Message);
Assert.AreEqual("TestUser", result.Data.ImportedBy);
}
[TestMethod]
public async Task ImportPackageAsync_InvalidPackage_ReturnsFailure()
{
// Arrange
var packagePath = "invalid_package.ovpkg";
var expectedError = Result<ModelPackageImportResultDto>.Fail("INVALID_PACKAGE", "模型包格式无效");
_modelPackageServiceMock
.Setup(x => x.ImportPackageAsync(packagePath, It.IsAny<CancellationToken>()))
.ReturnsAsync(expectedError);
// Act
var result = await _modelPackageServiceMock.Object.ImportPackageAsync(packagePath);
// Assert
Assert.IsFalse(result.Succeeded);
Assert.AreEqual("INVALID_PACKAGE", result.Code);
Assert.AreEqual("模型包格式无效", result.Message);
}
[TestMethod]
public async Task ImportPackageAsync_MissingFile_ReturnsFailure()
{
// Arrange
var packagePath = "missing_package.ovpkg";
var expectedError = Result<ModelPackageImportResultDto>.Fail("FILE_NOT_FOUND", "模型包文件不存在");
_modelPackageServiceMock
.Setup(x => x.ImportPackageAsync(packagePath, It.IsAny<CancellationToken>()))
.ReturnsAsync(expectedError);
// Act
var result = await _modelPackageServiceMock.Object.ImportPackageAsync(packagePath);
// Assert
Assert.IsFalse(result.Succeeded);
Assert.AreEqual("FILE_NOT_FOUND", result.Code);
Assert.AreEqual("模型包文件不存在", result.Message);
}
[TestMethod]
public async Task ActivatePackageAsync_ValidPackage_ReturnsSuccess()
{
// Arrange
var packageId = Guid.NewGuid();
var expectedResult = new ModelPackageActivationResultDto
{
ModelPackageId = packageId,
Status = ModelPackageActivationStatus.Activated,
Message = "激活成功",
ActivatedAtUtc = DateTime.UtcNow,
ActivatedBy = "TestUser"
};
_modelPackageServiceMock
.Setup(x => x.ActivatePackageAsync(packageId, It.IsAny<CancellationToken>()))
.ReturnsAsync(Result<ModelPackageActivationResultDto>.Success(expectedResult));
// Act
var result = await _modelPackageServiceMock.Object.ActivatePackageAsync(packageId);
// Assert
Assert.IsTrue(result.Succeeded);
Assert.IsNotNull(result.Data);
Assert.AreEqual(ModelPackageActivationStatus.Activated, result.Data.Status);
Assert.AreEqual("激活成功", result.Data.Message);
Assert.AreEqual("TestUser", result.Data.ActivatedBy);
}
[TestMethod]
public async Task ActivatePackageAsync_PackageNotFound_ReturnsFailure()
{
// Arrange
var packageId = Guid.NewGuid();
var expectedError = Result<ModelPackageActivationResultDto>.Fail("PACKAGE_NOT_FOUND", "模型包不存在");
_modelPackageServiceMock
.Setup(x => x.ActivatePackageAsync(packageId, It.IsAny<CancellationToken>()))
.ReturnsAsync(expectedError);
// Act
var result = await _modelPackageServiceMock.Object.ActivatePackageAsync(packageId);
// Assert
Assert.IsFalse(result.Succeeded);
Assert.AreEqual("PACKAGE_NOT_FOUND", result.Code);
Assert.AreEqual("模型包不存在", result.Message);
}
[TestMethod]
public async Task ActivatePackageAsync_AlreadyActivated_ReturnsFailure()
{
// Arrange
var packageId = Guid.NewGuid();
var expectedError = Result<ModelPackageActivationResultDto>.Fail("ALREADY_ACTIVATED", "模型包已激活");
_modelPackageServiceMock
.Setup(x => x.ActivatePackageAsync(packageId, It.IsAny<CancellationToken>()))
.ReturnsAsync(expectedError);
// Act
var result = await _modelPackageServiceMock.Object.ActivatePackageAsync(packageId);
// Assert
Assert.IsFalse(result.Succeeded);
Assert.AreEqual("ALREADY_ACTIVATED", result.Code);
Assert.AreEqual("模型包已激活", result.Message);
}
[TestMethod]
public async Task ImportAndActivate_CompleteWorkflow_ReturnsSuccess()
{
// Arrange
var packagePath = "test_package.ovpkg";
var packageId = Guid.NewGuid();
var importResult = new ModelPackageImportResultDto
{
ModelPackageId = packageId,
Status = ModelPackageImportStatus.Imported,
Message = "导入成功",
ImportedAtUtc = DateTime.UtcNow,
ImportedBy = "TestUser"
};
var activationResult = new ModelPackageActivationResultDto
{
ModelPackageId = packageId,
Status = ModelPackageActivationStatus.Activated,
Message = "激活成功",
ActivatedAtUtc = DateTime.UtcNow,
ActivatedBy = "TestUser"
};
_modelPackageServiceMock
.Setup(x => x.ImportPackageAsync(packagePath, It.IsAny<CancellationToken>()))
.ReturnsAsync(Result<ModelPackageImportResultDto>.Success(importResult));
_modelPackageServiceMock
.Setup(x => x.ActivatePackageAsync(packageId, It.IsAny<CancellationToken>()))
.ReturnsAsync(Result<ModelPackageActivationResultDto>.Success(activationResult));
// Act - Import
var importStep = await _modelPackageServiceMock.Object.ImportPackageAsync(packagePath);
// Assert - Import
Assert.IsTrue(importStep.Succeeded);
Assert.AreEqual(packageId, importStep.Data.ModelPackageId);
// Act - Activate
var activationStep = await _modelPackageServiceMock.Object.ActivatePackageAsync(packageId);
// Assert - Activate
Assert.IsTrue(activationStep.Succeeded);
Assert.AreEqual(packageId, activationStep.Data.ModelPackageId);
Assert.AreEqual(ModelPackageActivationStatus.Activated, activationStep.Data.Status);
}
[TestMethod]
public async Task ImportAndActivate_ImportFailure_StopsWorkflow()
{
// Arrange
var packagePath = "invalid_package.ovpkg";
var packageId = Guid.NewGuid();
var importError = Result<ModelPackageImportResultDto>.Fail("INVALID_FORMAT", "模型包格式无效");
_modelPackageServiceMock
.Setup(x => x.ImportPackageAsync(packagePath, It.IsAny<CancellationToken>()))
.ReturnsAsync(importError);
// Act
var importStep = await _modelPackageServiceMock.Object.ImportPackageAsync(packagePath);
// Assert
Assert.IsFalse(importStep.Succeeded);
Assert.AreEqual("INVALID_FORMAT", importStep.Code);
// Verify that activation was not attempted
_modelPackageServiceMock.Verify(
x => x.ActivatePackageAsync(It.IsAny<Guid>(), It.IsAny<CancellationToken>()),
Times.Never);
}
}