添加Haoliang.Tests单元测试项目
- 创建xUnit测试项目 - 添加Moq和FluentAssertions包 - 实现PingServiceTests (5个测试用例) - 实现DataParserServiceTests (9个测试用例) - 所有14个测试用例通过 - dotnet build 0 Errormain
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);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue