using System; using System.Collections.Generic; using CncModels.Dto; using CncModels.Dto.Alert; using CncService; using CncWebApi.Controllers; using Xunit; namespace CncWebApi.Tests { /// /// AlertController单元测试 /// 告警CRUD + 统计 + 批量处理 /// [Collection("Database")] public class AlertControllerTests { private readonly AlertController _controller; public AlertControllerTests() { TestDb.TruncateAll(); // 预置机床(告警外键依赖) TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at) VALUES ('测试地址', 'http://192.168.1.1', 1, 5, 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 ('CNC001', '机床1', 1, 1, '192.168.1.100', 1, 1, NOW(), NOW())"); _controller = ControllerFactory.CreateAlertController(); } #region 辅助方法 /// /// 插入一条告警 /// private int InsertAlert(string type = "offline", string title = "告警测试") { TestDb.Execute(@"INSERT INTO cnc_alert (machine_id, alert_type, title, is_resolved, created_at) VALUES (1, @type, @title, 0, NOW())", new { type, title }); return TestDb.QuerySingle("SELECT MAX(id) FROM cnc_alert"); } #endregion #region GetList - 告警列表 /// /// 测试:空数据库返回空列表 /// [Fact] public void GetList_EmptyDb_ShouldReturnEmpty() { var result = _controller.GetList(new AlertQuery()); var response = ControllerFactory.Extract>(result); ControllerFactory.AssertSuccess(response); Assert.Empty(response.Data.Items); } /// /// 测试:有告警数据时返回列表 /// [Fact] public void GetList_WithData_ShouldReturnItems() { InsertAlert(); var result = _controller.GetList(new AlertQuery()); var response = ControllerFactory.Extract>(result); Assert.NotEmpty(response.Data.Items); } #endregion #region GetStatistics - 告警统计 /// /// 测试:告警统计数据 /// [Fact] public void GetStatistics_ShouldReturnStats() { InsertAlert(); var result = _controller.GetStatistics(); var response = ControllerFactory.Extract(result); ControllerFactory.AssertSuccess(response); Assert.NotNull(response.Data); } #endregion #region Resolve - 处理告警 /// /// 测试:处理单条告警成功 /// [Fact] public void Resolve_Existing_ShouldSuccess() { int alertId = InsertAlert(); var result = _controller.Resolve(alertId); ControllerFactory.AssertSuccess(ControllerFactory.Extract(result)); // 验证已处理 int isResolved = TestDb.QuerySingle("SELECT is_resolved FROM cnc_alert WHERE id = @id", new { id = alertId }); Assert.Equal(1, isResolved); } /// /// 测试:处理不存在的告警不抛异常(Service层影响0行) /// [Fact] public void Resolve_NotExisting_ShouldNotThrow() { var result = _controller.Resolve(999); Assert.NotNull(result); } #endregion #region BatchResolve - 批量处理 /// /// 测试:批量处理告警成功 /// [Fact] public void BatchResolve_ValidIds_ShouldSuccess() { int id1 = InsertAlert("offline", "告警1"); int id2 = InsertAlert("offline", "告警2"); var result = _controller.BatchResolve(new BatchResolveRequest { Ids = new[] { id1, id2 } }); var response = ControllerFactory.Extract(result); ControllerFactory.AssertSuccess(response); } /// /// 测试:空ID数组抛出异常 /// [Fact] public void BatchResolve_EmptyIds_ShouldThrow() { Assert.Throws(() => _controller.BatchResolve(new BatchResolveRequest { Ids = new int[0] })); } #endregion } }