diff --git a/tests/CncService.Tests/CollectAddressServiceTests.cs b/tests/CncService.Tests/CollectAddressServiceTests.cs index d50dbc9..af2038c 100644 --- a/tests/CncService.Tests/CollectAddressServiceTests.cs +++ b/tests/CncService.Tests/CollectAddressServiceTests.cs @@ -184,8 +184,8 @@ namespace CncService.Tests VALUES ('M001', '机床1', 1, @addressId, '0.0.0.0', 1, 1, NOW(), NOW())", new { addressId }); - var result = _service.Delete(addressId); - Assert.False(result); + var ex = Assert.Throws(() => _service.Delete(addressId)); + Assert.Contains("机床", ex.Message); } // ======== ToggleEnabled ======== diff --git a/tests/CncService.Tests/DashboardServiceTests.cs b/tests/CncService.Tests/DashboardServiceTests.cs index cba34a9..9e152e1 100644 --- a/tests/CncService.Tests/DashboardServiceTests.cs +++ b/tests/CncService.Tests/DashboardServiceTests.cs @@ -19,6 +19,8 @@ namespace CncService.Tests public List GetProductionTrend(int days) => new List(); public object GetMachineStatusDistribution() => new object(); public List GetRecentAlerts(int count) => new List(); + public List GetProgramRank(DateTime startDate, DateTime endDate, int top, string sortOrder = "desc") => new List(); + public List GetProgramDistribution(DateTime startDate, DateTime endDate, int top = 10) => new List(); } public class FakeCollectorHeartbeatRepository : ICollectorHeartbeatRepository @@ -49,8 +51,21 @@ namespace CncService.Tests public bool UpdateValue(int id, string value) => true; } - public class DashboardServiceTests + [Collection("Database")] + public class DashboardServiceTests : IDisposable { + private readonly DashboardService _service; + + public DashboardServiceTests() + { + TestDb.TruncateAll(); + _service = ServiceFactory.CreateDashboardService(); + } + + public void Dispose() + { + TestDb.TruncateAll(); + } [Fact] public void GetCollectorStatus_With_NotInstalled_Service_Returns_NotInstalled_State() { @@ -73,7 +88,7 @@ namespace CncService.Tests Assert.NotNull(serviceStatusProp); var statusVal = statusProp.GetValue(resultObj) as string; var serviceStatusVal = serviceStatusProp.GetValue(resultObj) as string; - Assert.Equal("stopped", statusVal); + Assert.Equal("not_installed", statusVal); Assert.Equal("NotInstalled", serviceStatusVal); } @@ -114,5 +129,72 @@ namespace CncService.Tests Assert.Equal("Starting", serviceStatusVal); Assert.Equal("running", statusVal); } + + // ======== GetProgramRank ======== + + [Fact] + public void GetProgramRank_无数据_返回空列表() + { + var result = _service.GetProgramRank(null, null); + Assert.NotNull(result); + Assert.Empty(result); + } + + [Fact] + public void GetProgramRank_有数据_返回排行列表() + { + // 插入测试数据 + TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at) + VALUES ('测试地址', 'http://test', 1, 30, 1, NOW(), NOW())"); + TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, created_at, updated_at) + VALUES ('M001', '机床1', 1, 1, '0.0.0.0', 1, 1, NOW(), NOW())"); + TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, created_at, updated_at) + VALUES ('M002', '机床2', 1, 1, '0.0.0.0', 1, 1, NOW(), NOW())"); + TestDb.Execute(@"INSERT INTO cnc_production_segment (machine_id, production_date, program_name, start_time, start_part_count, end_part_count, quantity, is_settled, created_at, updated_at) + VALUES (1, CURDATE(), 'O0001', NOW(), 0, 100, 100, 1, NOW(), NOW())"); + TestDb.Execute(@"INSERT INTO cnc_production_segment (machine_id, production_date, program_name, start_time, start_part_count, end_part_count, quantity, is_settled, created_at, updated_at) + VALUES (2, CURDATE(), 'O0001', NOW(), 0, 50, 50, 1, NOW(), NOW())"); + + var result = _service.GetProgramRank(DateTime.Today, DateTime.Today); + Assert.NotEmpty(result); + Assert.Equal("O0001", result[0].ProgramName); + Assert.Equal(150, result[0].TotalQuantity); + Assert.Equal(2, result[0].MachineCount); + Assert.Equal(1, result[0].Rank); + } + + // ======== GetProgramDistribution ======== + + [Fact] + public void GetProgramDistribution_无数据_返回空列表() + { + var result = _service.GetProgramDistribution(null, null); + Assert.NotNull(result); + Assert.Empty(result); + } + + [Fact] + public void GetProgramDistribution_有数据_返回分布列表() + { + // 插入测试数据 + TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at) + VALUES ('测试地址', 'http://test', 1, 30, 1, NOW(), NOW())"); + TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, created_at, updated_at) + VALUES ('M001', '机床1', 1, 1, '0.0.0.0', 1, 1, NOW(), NOW())"); + TestDb.Execute(@"INSERT INTO cnc_production_segment (machine_id, production_date, program_name, start_time, start_part_count, end_part_count, quantity, is_settled, created_at, updated_at) + VALUES (1, CURDATE(), 'O0001', NOW(), 0, 80, 80, 1, NOW(), NOW())"); + TestDb.Execute(@"INSERT INTO cnc_production_segment (machine_id, production_date, program_name, start_time, start_part_count, end_part_count, quantity, is_settled, created_at, updated_at) + VALUES (1, CURDATE(), 'O0002', NOW(), 0, 20, 20, 1, NOW(), NOW())"); + + var result = _service.GetProgramDistribution(DateTime.Today, DateTime.Today); + Assert.NotEmpty(result); + Assert.Equal(2, result.Count); + Assert.Equal("O0001", result[0].ProgramName); + Assert.Equal(80, result[0].TotalQuantity); + Assert.Equal(80m, result[0].Percentage); + Assert.Equal("O0002", result[1].ProgramName); + Assert.Equal(20, result[1].TotalQuantity); + Assert.Equal(20m, result[1].Percentage); + } } } diff --git a/tests/CncService.Tests/MachineServiceTests.cs b/tests/CncService.Tests/MachineServiceTests.cs index 30ec331..6a62c99 100644 --- a/tests/CncService.Tests/MachineServiceTests.cs +++ b/tests/CncService.Tests/MachineServiceTests.cs @@ -284,5 +284,32 @@ namespace CncService.Tests var ex = Assert.Throws(() => _service.ToggleEnabled(0)); Assert.Equal(ErrorCode.BadRequest, ex.Code); } + + // ======== GetLatestTags ======== + + [Fact] + public void GetLatestTags_机床不存在_返回空列表() + { + // 机床ID不存在时,MachineLatestTagRepository 查询不到 device_code,返回空列表 + var result = _service.GetLatestTags(99999); + Assert.NotNull(result); + Assert.Empty(result); + } + + // ======== GetCollectRecords ======== + + [Fact] + public void GetCollectRecords_无效ID_抛出BadRequest异常() + { + var ex = Assert.Throws(() => _service.GetCollectRecords(0)); + Assert.Equal(ErrorCode.BadRequest, ex.Code); + } + + [Fact] + public void GetCollectRecords_机床不存在_抛出NotFound异常() + { + var ex = Assert.Throws(() => _service.GetCollectRecords(99999)); + Assert.Equal(ErrorCode.NotFound, ex.Code); + } } } diff --git a/tests/CncService.Tests/ProductionServiceTests.cs b/tests/CncService.Tests/ProductionServiceTests.cs index fae2557..9cbc80f 100644 --- a/tests/CncService.Tests/ProductionServiceTests.cs +++ b/tests/CncService.Tests/ProductionServiceTests.cs @@ -134,5 +134,115 @@ namespace CncService.Tests var count = TestDb.QuerySingle("SELECT COUNT(*) FROM cnc_production_adjustment"); Assert.Equal(1, count); } + + // ======== GetMachineSummary ======== + + [Fact] + public void GetMachineSummary_无数据_返回0值() + { + var result = _service.GetMachineSummary(null, null, null); + Assert.NotNull(result); + Assert.Equal(0, result.TotalQuantity); + Assert.Equal(0, result.RunningMachineCount); + } + + [Fact] + public void GetMachineSummary_有数据_返回正确统计() + { + // 插入测试数据:2台机床,各生产一个程序 + TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at) + VALUES ('测试地址', 'http://test', 1, 30, 1, NOW(), NOW())"); + TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, created_at, updated_at) + VALUES ('M001', '机床1', 1, 1, '0.0.0.0', 1, 1, NOW(), NOW())"); + TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, created_at, updated_at) + VALUES ('M002', '机床2', 1, 1, '0.0.0.0', 1, 1, NOW(), NOW())"); + TestDb.Execute(@"INSERT INTO cnc_production_segment (machine_id, production_date, program_name, start_time, start_part_count, end_part_count, quantity, is_settled, created_at, updated_at) + VALUES (1, CURDATE(), 'O0001', NOW(), 0, 100, 100, 1, NOW(), NOW())"); + TestDb.Execute(@"INSERT INTO cnc_production_segment (machine_id, production_date, program_name, start_time, start_part_count, end_part_count, quantity, is_settled, created_at, updated_at) + VALUES (2, CURDATE(), 'O0002', NOW(), 0, 50, 50, 1, NOW(), NOW())"); + + var result = _service.GetMachineSummary(DateTime.Today, DateTime.Today, null); + Assert.Equal(150, result.TotalQuantity); + Assert.Equal(2, result.RunningMachineCount); + Assert.Equal(75m, result.AvgPerMachine); + Assert.NotEmpty(result.TopMachineName); + } + + // ======== GetMachineList ======== + + [Fact] + public void GetMachineList_无数据_返回空列表() + { + var result = _service.GetMachineList(null, null, null, null); + Assert.NotNull(result); + Assert.Empty(result); + } + + [Fact] + public void GetMachineList_有数据_返回排行() + { + TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at) + VALUES ('测试地址', 'http://test', 1, 30, 1, NOW(), NOW())"); + TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, created_at, updated_at) + VALUES ('M001', '机床1', 1, 1, '0.0.0.0', 1, 1, NOW(), NOW())"); + TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, created_at, updated_at) + VALUES ('M002', '机床2', 1, 1, '0.0.0.0', 1, 1, NOW(), NOW())"); + TestDb.Execute(@"INSERT INTO cnc_production_segment (machine_id, production_date, program_name, start_time, start_part_count, end_part_count, quantity, is_settled, created_at, updated_at) + VALUES (1, CURDATE(), 'O0001', NOW(), 0, 100, 100, 1, NOW(), NOW())"); + TestDb.Execute(@"INSERT INTO cnc_production_segment (machine_id, production_date, program_name, start_time, start_part_count, end_part_count, quantity, is_settled, created_at, updated_at) + VALUES (2, CURDATE(), 'O0002', NOW(), 0, 50, 50, 1, NOW(), NOW())"); + + var result = _service.GetMachineList(DateTime.Today, DateTime.Today, null, null); + Assert.NotEmpty(result); + Assert.Equal(2, result.Count); + Assert.Equal(1, result[0].Rank); + Assert.Equal("机床1", result[0].MachineName); + Assert.Equal(100, result[0].TotalQuantity); + Assert.Equal(2, result[1].Rank); + Assert.Equal("机床2", result[1].MachineName); + Assert.Equal(50, result[1].TotalQuantity); + } + + // ======== GetWorkerSummary ======== + + [Fact] + public void GetWorkerSummary_无数据_返回0值() + { + var result = _service.GetWorkerSummary(null, null); + Assert.NotNull(result); + Assert.Equal(0, result.TotalQuantity); + Assert.Equal(0, result.ActiveWorkerCount); + } + + // ======== GetWorkerList ======== + + [Fact] + public void GetWorkerList_无数据_返回空列表() + { + var result = _service.GetWorkerList(null, null, null); + Assert.NotNull(result); + Assert.Empty(result); + } + + // ======== GetProgramSummary ======== + + [Fact] + public void GetProgramSummary_无数据_返回0值() + { + var result = _service.GetProgramSummary(null, null, null); + Assert.NotNull(result); + Assert.Equal(0, result.TotalQuantity); + Assert.Equal(0, result.RunningProgramCount); + } + + // ======== GetProgramList ======== + + [Fact] + public void GetProgramList_无数据_返回空列表() + { + var result = _service.GetProgramList(null, null, null); + Assert.NotNull(result); + Assert.Empty(result); + } } } diff --git a/tests/CncService.Tests/ServiceFactory.cs b/tests/CncService.Tests/ServiceFactory.cs index 1f04b5a..b272001 100644 --- a/tests/CncService.Tests/ServiceFactory.cs +++ b/tests/CncService.Tests/ServiceFactory.cs @@ -35,6 +35,8 @@ namespace CncService.Tests // ======== Repository 创建(日志库) ======== private static CollectorHeartbeatRepository NewCollectorHeartbeatRepo() => new CollectorHeartbeatRepository(ConnStrLog); private static CollectRawRepository NewCollectRawRepo() => new CncRepository.Impl.Log.CollectRawRepository(ConnStrLog); + private static MachineLatestTagRepository NewLatestTagRepo() => new MachineLatestTagRepository(ConnStrLog, ConnStr); + private static CollectAnalysisRepository NewCollectAnalysisRepo() => new CollectAnalysisRepository(ConnStrLog); // ======== Service 创建 ======== @@ -59,7 +61,7 @@ namespace CncService.Tests /// 创建MachineService public static MachineService CreateMachineService() { - return new MachineService(NewMachineRepo(), NewCollectAddressRepo(), NewWorkerMachineRepo(), NewBrandRepo()); + return new MachineService(NewMachineRepo(), NewCollectAddressRepo(), NewWorkerMachineRepo(), NewBrandRepo(), NewLatestTagRepo(), NewCollectAnalysisRepo()); } /// 创建CollectAddressService