添加Haoliang.Tests单元测试项目

- 创建xUnit测试项目
- 添加Moq和FluentAssertions包
- 实现PingServiceTests (5个测试用例)
- 实现DataParserServiceTests (9个测试用例)
- 所有14个测试用例通过
- dotnet build 0 Error
main
821644@qq.com 3 weeks ago
parent e2c0689dcb
commit 5b54ca569e

@ -0,0 +1,161 @@
using Xunit;
using Moq;
using FluentAssertions;
using Microsoft.Extensions.Logging;
using Haoliang.Core.Services;
using Haoliang.Models.DataCollection;
namespace Haoliang.Tests;
public class DataParserServiceTests
{
private readonly DataParserService _parserService;
private readonly Mock<ILogger<DataParserService>> _loggerMock;
public DataParserServiceTests()
{
_loggerMock = new Mock<ILogger<DataParserService>>();
_parserService = new DataParserService(_loggerMock.Object);
}
[Fact]
public async Task ParseRawDataAsync_ValidJson_ReturnsDeviceData()
{
var json = @"{
""device"": ""CNC001"",
""desc"": ""1"",
""tags"": [
{""id"": ""Tag5"", ""desc"": """", ""quality"": ""good"", ""value"": ""PROGRAM001"", ""time"": ""2024-01-01T10:00:00""},
{""id"": ""Tag8"", ""desc"": """", ""quality"": ""good"", ""value"": ""100"", ""time"": ""2024-01-01T10:00:00""}
]
}";
var result = await _parserService.ParseRawDataAsync(json, 1);
result.Should().NotBeNull();
result.DeviceName.Should().Be("CNC001");
result.Tags.Should().NotBeNull();
result.Tags.Should().ContainKey("Tag5");
}
[Fact]
public async Task ParseRawDataAsync_InvalidJson_ThrowsException()
{
var json = "invalid json";
var action = async () => await _parserService.ParseRawDataAsync(json, 1);
await action.Should().ThrowAsync<InvalidOperationException>();
}
[Fact]
public async Task ParseRawDataAsync_ValidJson_ContainsTags()
{
var json = @"{
""device"": ""CNC001"",
""desc"": ""1"",
""tags"": [
{""id"": ""Tag5"", ""desc"": """", ""quality"": ""good"", ""value"": ""TEST_PROGRAM"", ""time"": ""2024-01-01T10:00:00""}
]
}";
var result = await _parserService.ParseRawDataAsync(json, 1);
result.Should().NotBeNull();
result.Tags.Should().ContainKey("Tag5");
result.Tags!["Tag5"].Value.Should().Be("TEST_PROGRAM");
}
[Fact]
public async Task ParseRawDataAsync_ExtractsTag8Value()
{
var json = @"{
""device"": ""CNC001"",
""desc"": ""1"",
""tags"": [
{""id"": ""Tag8"", ""desc"": """", ""quality"": ""good"", ""value"": ""150"", ""time"": ""2024-01-01T10:00:00""}
]
}";
var result = await _parserService.ParseRawDataAsync(json, 1);
result.Should().NotBeNull();
result.Tags.Should().ContainKey("Tag8");
}
[Fact]
public async Task ParseRawDataAsync_RemovesDecimalSuffix()
{
var json = @"{
""device"": ""CNC001"",
""desc"": ""1"",
""tags"": [
{""id"": ""Tag8"", ""desc"": """", ""quality"": ""good"", ""value"": ""150.00000"", ""time"": ""2024-01-01T10:00:00""}
]
}";
var result = await _parserService.ParseRawDataAsync(json, 1);
result.Should().NotBeNull();
result.Tags.Should().ContainKey("Tag8");
}
[Fact]
public async Task ParseRawDataAsync_ExtractsIoStatus()
{
var json = @"{
""device"": ""CNC001"",
""desc"": ""1"",
""tags"": [
{""id"": ""_io_status"", ""desc"": """", ""quality"": ""good"", ""value"": ""RUN"", ""time"": ""2024-01-01T10:00:00""}
]
}";
var result = await _parserService.ParseRawDataAsync(json, 1);
result.Should().NotBeNull();
result.Tags.Should().ContainKey("_io_status");
result.Tags!["_io_status"].Value.Should().Be("RUN");
}
[Fact]
public void ValidateDataFormat_ValidJson_ReturnsTrue()
{
var json = @"{""device"": ""CNC001"", ""tags"": []}";
var result = _parserService.ValidateDataFormat(json);
result.Should().BeTrue();
}
[Fact]
public void ValidateDataFormat_InvalidJson_ReturnsFalse()
{
var json = "not valid json";
var result = _parserService.ValidateDataFormat(json);
result.Should().BeFalse();
}
[Fact]
public async Task ParseMultiDeviceDataAsync_MultipleDevices_ReturnsAll()
{
var json = @"[
{
""device"": ""CNC001"",
""desc"": ""1"",
""tags"": []
},
{
""device"": ""CNC002"",
""desc"": ""2"",
""tags"": []
}
]";
var result = await _parserService.ParseMultiDeviceDataAsync(json, 1);
result.Should().HaveCount(2);
}
}

@ -0,0 +1 @@
global using Xunit;

@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="8.9.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Haoliang.Core\Haoliang.Core.csproj" />
<ProjectReference Include="..\Haoliang.Models\Haoliang.Models.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,74 @@
using Xunit;
using Moq;
using FluentAssertions;
using Microsoft.Extensions.Logging;
using Haoliang.Core.Services;
using Haoliang.Models.Device;
namespace Haoliang.Tests;
public class PingServiceTests
{
private readonly PingService _pingService;
private readonly Mock<ILogger<PingService>> _loggerMock;
public PingServiceTests()
{
_loggerMock = new Mock<ILogger<PingService>>();
_pingService = new PingService(_loggerMock.Object);
}
[Fact]
public async Task PingAsync_Success_ReturnsSuccessResult()
{
var result = await _pingService.PingAsync(1, "127.0.0.1");
result.Should().NotBeNull();
result.DeviceId.Should().Be(1);
result.IpAddress.Should().Be("127.0.0.1");
result.Timestamp.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(5));
}
[Fact]
public async Task PingAsync_InvalidIp_ReturnsFailureResult()
{
var result = await _pingService.PingAsync(999, "invalid-ip");
result.Should().NotBeNull();
result.DeviceId.Should().Be(999);
result.Success.Should().BeFalse();
result.ErrorMessage.Should().NotBeNullOrEmpty();
}
[Fact]
public async Task IsReachableAsync_ValidIp_ReturnsTrue()
{
var result = await _pingService.IsReachableAsync("127.0.0.1");
result.Should().BeTrue();
}
[Fact]
public async Task IsReachableAsync_InvalidIp_ReturnsFalse()
{
var result = await _pingService.IsReachableAsync("10.255.255.1", TimeSpan.FromSeconds(1));
result.Should().BeFalse();
}
[Fact]
public async Task PingAllAsync_MultipleDevices_ReturnsAllResults()
{
var devices = new List<(int DeviceId, string IpAddress)>
{
(1, "127.0.0.1"),
(2, "127.0.0.1")
};
var results = await _pingService.PingAllAsync(devices);
results.Should().HaveCount(2);
results.Should().Contain(r => r.DeviceId == 1);
results.Should().Contain(r => r.DeviceId == 2);
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,13 @@
{
"runtimeOptions": {
"tfm": "net8.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "8.0.0"
},
"configProperties": {
"System.Reflection.NullabilityInfoContext.IsSupported": true,
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
}
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save