test(models): CncModels.Tests 46个测试全部通过

- EnumTests: 9个snake_case枚举约定验证 + LogLevel大写验证
- ConstantsTests: 20个TableName精确值 + 3个SensitiveConfigKey + 6个ErrorCode数字校验
- EntityTests: 20个实体属性赋值读回测试
- PagedQueryTests: 边界值测试(page=0/-1/pageSize=0/101自动修正)
- PagedResultTests: TotalPages计算(空数据/满页/跨页/除零保护)
- ApiResponseTests: Success/Fail工厂方法+null数据+复杂对象
- DtoTests: LoginRequest/MachineQuery/CreateMachineRequest/MachineListItem赋值测试
main
haoliang 1 week ago
parent 7686930525
commit 5ec37e6724

@ -0,0 +1,78 @@
using System.Collections.Generic;
using Xunit;
using CncModels.Dto;
namespace CncModels.Tests
{
/// <summary>
/// ApiResponse<T> 单元测试
/// </summary>
public class ApiResponseTests
{
[Fact]
/// <summary>
/// 成功响应Code=0, Message=success, Data=传入值
/// </summary>
public void Success_Returns_Code_0_Message_Success_With_Data()
{
// Arrange
var data = "ok";
// Act
var resp = ApiResponse<string>.Success(data);
// Assert
Assert.Equal(0, resp.Code);
Assert.Equal("success", resp.Message);
Assert.Equal(data, resp.Data);
}
[Fact]
/// <summary>
/// 成功响应:自定义信息
/// </summary>
public void Success_With_Custom_Message()
{
var resp = ApiResponse<string>.Success("payload", "custom");
Assert.Equal(0, resp.Code);
Assert.Equal("custom", resp.Message);
Assert.Equal("payload", resp.Data);
}
[Fact]
/// <summary>
/// 失败响应:非零错误码且数据为 null
/// </summary>
public void Fail_Returns_NonZero_Code_And_Null_Data()
{
var resp = ApiResponse<string>.Fail(400, "bad request");
Assert.Equal(400, resp.Code);
Assert.Equal("bad request", resp.Message);
Assert.Null(resp.Data);
}
[Fact]
/// <summary>
/// 成功响应:数据为 null 的情况
/// </summary>
public void Success_With_Null_Data()
{
var resp = ApiResponse<string>.Success(null);
Assert.Equal(0, resp.Code);
Assert.Equal("success", resp.Message);
Assert.Null(resp.Data);
}
[Fact]
/// <summary>
/// 成功响应:复杂对象数据
/// </summary>
public void Success_With_Complex_Data()
{
var data = new List<int> { 1, 2, 3 };
var resp = ApiResponse<List<int>>.Success(data);
Assert.Equal(0, resp.Code);
Assert.Equal("success", resp.Message);
Assert.Equal(data, resp.Data);
}
}
}

@ -0,0 +1,101 @@
using System;
using System.Reflection;
using System.Text;
using Xunit;
using CncModels.Constants;
namespace CncModels.Tests
{
/// <summary>
/// 常量类测试TableName、SensitiveConfigKey、ErrorCode 的常量值应符合命名约定与格式要求。
/// </summary>
public class ConstantsTests
{
/// <summary>
/// 验证 TableName 的 20 个表名常量值与数据库实际表名一致
/// 覆盖场景全部20张表的精确值校验
/// </summary>
[Fact]
public void TableName_AllConstants_MatchDatabaseTableNames()
{
// 业务库 17 张表
Assert.Equal("cnc_workshop", TableName.Workshop);
Assert.Equal("cnc_brand", TableName.Brand);
Assert.Equal("cnc_brand_field_mapping", TableName.BrandFieldMapping);
Assert.Equal("cnc_collect_address", TableName.CollectAddress);
Assert.Equal("cnc_machine", TableName.Machine);
Assert.Equal("cnc_worker", TableName.Worker);
Assert.Equal("cnc_worker_machine", TableName.WorkerMachine);
Assert.Equal("cnc_collect_record", TableName.CollectRecord);
Assert.Equal("cnc_production_segment", TableName.ProductionSegment);
Assert.Equal("cnc_machine_daily_status", TableName.MachineDailyStatus);
Assert.Equal("cnc_daily_production", TableName.DailyProduction);
Assert.Equal("cnc_worker_daily_summary", TableName.WorkerDailySummary);
Assert.Equal("cnc_production_adjustment", TableName.ProductionAdjustment);
Assert.Equal("cnc_alert", TableName.Alert);
Assert.Equal("cnc_sys_config", TableName.SysConfig);
Assert.Equal("cnc_screen_config", TableName.ScreenConfig);
Assert.Equal("cnc_screen_filter", TableName.ScreenFilter);
// 日志库 3 张表
Assert.Equal("log_collect_raw", TableName.LogCollectRaw);
Assert.Equal("log_system", TableName.LogSystem);
Assert.Equal("log_collector_heartbeat", TableName.LogCollectorHeartbeat);
}
/// <summary>
/// AAA验证 SensitiveConfigKey 的 3 个敏感键常量值应为 snake_case 风格。
/// </summary>
[Fact]
public void SensitiveConfigKey_Constants_ShouldFollowSnakeCase()
{
Type t = typeof(SensitiveConfigKey);
var fields = t.GetFields(BindingFlags.Public | BindingFlags.Static);
Assert.Equal(3, fields.Length);
foreach (var f in fields)
{
if (f.FieldType != typeof(string)) continue;
string value = (string)f.GetValue(null);
string expected = ToSnakeCase(f.Name);
Assert.Equal(expected, value);
}
}
/// <summary>
/// AAA验证 ErrorCode 的 6 个错误码常量值应为纯数字字符串。
/// </summary>
[Fact]
public void ErrorCode_Constants_ShouldBeNumericStrings()
{
Type t = typeof(ErrorCode);
var fields = t.GetFields(BindingFlags.Public | BindingFlags.Static);
// 至少应有 6 个错误码常量,若有更多也应遵循数字字符串规则
Assert.True(fields.Length >= 6, "ErrorCode 至少应包含 6 个常量");
foreach (var f in fields)
{
if (f.FieldType != typeof(string)) continue;
string value = (string)f.GetValue(null);
Assert.Matches("^[0-9]+$", value);
}
}
private string ToSnakeCase(string input)
{
if (string.IsNullOrEmpty(input)) return input;
var sb = new StringBuilder();
for (int i = 0; i < input.Length; i++)
{
char c = input[i];
if (char.IsUpper(c))
{
if (i > 0) sb.Append('_');
sb.Append(char.ToLowerInvariant(c));
}
else
{
sb.Append(c);
}
}
return sb.ToString();
}
}
}

@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using Xunit;
using CncModels.Dto.Login;
using CncModels.Dto.Machine;
namespace CncModels.Tests
{
/// <summary>
/// DTO 属性赋值测试(对关键 DTO 的简单结构进行读写回填验证)
/// </summary>
public class DtoTests
{
[Fact]
/// <summary>
/// LoginRequest 属性赋值读取回填
/// </summary>
public void LoginRequest_Property_Assignment()
{
// Arrange
var req = new LoginRequest
{
Username = "user1",
Password = "pwd",
RememberMe = true
};
// Assert
Assert.Equal("user1", req.Username);
Assert.Equal("pwd", req.Password);
Assert.True(req.RememberMe);
}
[Fact]
/// <summary>
/// MachineQuery 继承自 PagedQuery 且字段赋值正确
/// </summary>
public void MachineQuery_Inherits_PagedQuery_And_Sets_Others()
{
var q = new MachineQuery
{
Page = 2,
PageSize = 5,
Keyword = "lathe",
WorkshopId = 3,
IsOnline = 1,
BrandId = 7
};
Assert.Equal(2, q.Page);
Assert.Equal(5, q.PageSize);
Assert.Equal("lathe", q.Keyword);
Assert.Equal(3, q.WorkshopId);
Assert.Equal(1, q.IsOnline);
Assert.Equal(7, q.BrandId);
Assert.Equal(5, q.Offset); // (2-1)*5
}
[Fact]
/// <summary>
/// CreateMachineRequest 属性赋值读取回填
/// </summary>
public void CreateMachineRequest_Property_Assignment()
{
var req = new CreateMachineRequest
{
DeviceCode = "D1",
Name = "Machine 1",
WorkshopId = 2,
CollectAddressId = 3,
IpAddress = "192.168.1.10",
BrandId = 8
};
Assert.Equal("D1", req.DeviceCode);
Assert.Equal("Machine 1", req.Name);
Assert.Equal(2, req.WorkshopId);
Assert.Equal(3, req.CollectAddressId);
Assert.Equal("192.168.1.10", req.IpAddress);
Assert.Equal(8, req.BrandId);
}
[Fact]
/// <summary>
/// MachineListItem 属性赋值读取回填
/// </summary>
public void MachineListItem_Property_Assignment()
{
var item = new MachineListItem
{
Id = 1,
DeviceCode = "M1",
Name = "Machine 1",
WorkshopId = 2,
WorkshopName = "Workshop A",
CollectAddressId = 4,
BrandId = 8,
BrandName = "BrandX",
IpAddress = "10.0.0.1",
IsEnabled = 1,
IsOnline = 1,
WorkerId = 9,
WorkerName = "Worker1",
LastProgramName = "P1",
LastCollectTime = new DateTime(2026, 4, 1)
};
Assert.Equal(1, item.Id);
Assert.Equal("M1", item.DeviceCode);
Assert.Equal("Machine 1", item.Name);
Assert.Equal(2, item.WorkshopId);
Assert.Equal("Workshop A", item.WorkshopName);
Assert.Equal(4, item.CollectAddressId);
Assert.Equal(8, item.BrandId);
Assert.Equal("BrandX", item.BrandName);
Assert.Equal("10.0.0.1", item.IpAddress);
Assert.Equal(1, item.IsEnabled);
Assert.Equal(1, item.IsOnline);
Assert.Equal(9, item.WorkerId);
Assert.Equal("Worker1", item.WorkerName);
Assert.Equal("P1", item.LastProgramName);
Assert.Equal(new DateTime(2026, 4, 1), item.LastCollectTime);
}
}
}

@ -0,0 +1,775 @@
using System;
using CncModels.Entity;
using Xunit;
namespace CncModels.Tests
{
public class EntityTests
{
// Workshop
[Fact]
public void Workshop_DefaultsAndAssignments_ReturnsCorrectValues()
{
// Arrange: defaults
var w0 = new Workshop();
Assert.Equal(0, w0.Id);
Assert.Null(w0.Name);
Assert.Equal(0, w0.SortOrder);
Assert.Equal(0, w0.IsEnabled);
Assert.Equal(default(DateTime), w0.CreatedAt);
Assert.Equal(default(DateTime), w0.UpdatedAt);
// Act: assign all fields
var w = new Workshop
{
Id = 1,
Name = "A栋",
SortOrder = 2,
IsEnabled = 1,
CreatedAt = new DateTime(2026, 4, 28),
UpdatedAt = new DateTime(2026, 4, 29)
};
// Assert: values
Assert.Equal(1, w.Id);
Assert.Equal("A栋", w.Name);
Assert.Equal(2, w.SortOrder);
Assert.Equal(1, w.IsEnabled);
Assert.Equal(new DateTime(2026, 4, 28), w.CreatedAt);
Assert.Equal(new DateTime(2026, 4, 29), w.UpdatedAt);
}
// Brand
[Fact]
public void Brand_DefaultsAndAssignments_ReturnsCorrectValues()
{
var b0 = new Brand();
Assert.Equal(0, b0.Id);
Assert.Null(b0.BrandName);
Assert.Null(b0.DeviceField);
Assert.Null(b0.TagsPath);
Assert.Equal(0, b0.IsEnabled);
Assert.Equal(default(DateTime), b0.CreatedAt);
Assert.Equal(default(DateTime), b0.UpdatedAt);
var b = new Brand
{
Id = 3,
BrandName = "BrandX",
DeviceField = "fieldX",
TagsPath = "/tags/x",
IsEnabled = 1,
CreatedAt = new DateTime(2026, 4, 28),
UpdatedAt = new DateTime(2026, 4, 29)
};
Assert.Equal(3, b.Id);
Assert.Equal("BrandX", b.BrandName);
Assert.Equal("fieldX", b.DeviceField);
Assert.Equal("/tags/x", b.TagsPath);
Assert.Equal(1, b.IsEnabled);
Assert.Equal(new DateTime(2026, 4, 28), b.CreatedAt);
Assert.Equal(new DateTime(2026, 4, 29), b.UpdatedAt);
}
// BrandFieldMapping
[Fact]
public void BrandFieldMapping_DefaultsAndAssignments_ReturnsCorrectValues()
{
var m0 = new BrandFieldMapping();
Assert.Equal(0, m0.Id);
Assert.Equal(0, m0.BrandId);
Assert.Null(m0.StandardField);
Assert.Null(m0.FieldName);
Assert.Null(m0.MatchBy);
Assert.Null(m0.DataType);
Assert.Equal(0, m0.IsRequired);
Assert.Equal(default(DateTime), m0.CreatedAt);
var m = new BrandFieldMapping
{
Id = 1,
BrandId = 2,
StandardField = "Model",
FieldName = "mdl",
MatchBy = "equals",
DataType = "string",
IsRequired = 1,
CreatedAt = new DateTime(2026, 4, 28)
};
Assert.Equal(1, m.Id);
Assert.Equal(2, m.BrandId);
Assert.Equal("Model", m.StandardField);
Assert.Equal("mdl", m.FieldName);
Assert.Equal("equals", m.MatchBy);
Assert.Equal("string", m.DataType);
Assert.Equal(1, m.IsRequired);
Assert.Equal(new DateTime(2026, 4, 28), m.CreatedAt);
}
// CollectAddress
[Fact]
public void CollectAddress_DefaultsAndAssignments_ReturnsCorrectValues()
{
var a0 = new CollectAddress();
Assert.Equal(0, a0.Id);
Assert.Null(a0.Name);
Assert.Null(a0.Url);
Assert.Equal(0, a0.BrandId);
Assert.Equal(0, a0.CollectInterval);
Assert.Equal(0, a0.IsEnabled);
Assert.Null(a0.LastCollectTime);
Assert.Null(a0.LastCollectStatus);
Assert.Equal(0, a0.FailCount);
Assert.Equal(default(DateTime), a0.CreatedAt);
Assert.Equal(default(DateTime), a0.UpdatedAt);
var a = new CollectAddress
{
Id = 10,
Name = "地址1",
Url = "http://127.0.0.1",
BrandId = 5,
CollectInterval = 60,
IsEnabled = 1,
LastCollectTime = new DateTime(2026, 4, 28),
LastCollectStatus = "OK",
FailCount = 0,
CreatedAt = new DateTime(2026, 4, 29),
UpdatedAt = new DateTime(2026, 4, 30)
};
Assert.Equal(10, a.Id);
Assert.Equal("地址1", a.Name);
Assert.Equal("http://127.0.0.1", a.Url);
Assert.Equal(5, a.BrandId);
Assert.Equal(60, a.CollectInterval);
Assert.Equal(1, a.IsEnabled);
Assert.Equal(new DateTime(2026, 4, 28), a.LastCollectTime);
Assert.Equal("OK", a.LastCollectStatus);
Assert.Equal(0, a.FailCount);
Assert.Equal(new DateTime(2026, 4, 29), a.CreatedAt);
Assert.Equal(new DateTime(2026, 4, 30), a. UpdatedAt);
}
// CollectRecord
[Fact]
public void CollectRecord_DefaultsAndAssignments_ReturnsCorrectValues()
{
var r0 = new CollectRecord();
Assert.Equal(0L, r0.Id);
Assert.Equal(default(DateTime), r0.CollectTime);
Assert.Equal(0, r0.MachineId);
Assert.Null(r0.ProgramName);
Assert.Null(r0.DeviceStatus);
Assert.Null(r0.RunStatus);
Assert.Null(r0.OperateMode);
Assert.Null(r0.ExtraData);
var r = new CollectRecord
{
Id = 1234567890123,
MachineId = 7,
CollectTime = new DateTime(2026, 4, 28, 12, 0, 0),
DeviceTime = new DateTime(2026, 4, 28, 12, 0, 1),
ProgramName = "Prog1",
PartCount = 99.5m,
DeviceStatus = "OK",
RunStatus = "Running",
OperateMode = "Auto",
SpindleSpeedSet = 1500.0m,
FeedSpeedSet = 200.0m,
SpindleSpeedActual = 1499.0m,
FeedSpeedActual = 198.0m,
SpindleLoad = 75.0m,
SpindleOverride = 1.0m,
PowerOnTime = 3600.0m,
RunTime = 7200.0m,
CuttingTime = 1800.0m,
CycleTime = 300.0m,
MachiningStatus = "Machining",
ExtraData = "{}",
};
// Partial assertions to cover types
Assert.Equal(1234567890123, r.Id);
Assert.Equal(7, r.MachineId);
Assert.Equal(new DateTime(2026, 4, 28, 12, 0, 0), r.CollectTime);
Assert.Equal("Prog1", r.ProgramName);
Assert.Equal(99.5m, r.PartCount);
Assert.Equal("OK", r.DeviceStatus);
Assert.Equal("Running", r.RunStatus);
Assert.Equal(1500.0m, r.SpindleSpeedSet);
Assert.Equal(200.0m, r.FeedSpeedSet);
Assert.Equal("Machining", r.MachiningStatus);
}
// ProductionSegment
[Fact]
public void ProductionSegment_DefaultsAndAssignments_ReturnsCorrectValues()
{
var s0 = new ProductionSegment();
Assert.Equal(0L, s0.Id);
Assert.Equal(0, s0.MachineId);
Assert.Null(s0.ProgramName);
Assert.Equal(default(DateTime), s0.ProductionDate);
Assert.Equal(default(DateTime), s0.StartTime);
Assert.Null(s0.EndTime);
Assert.Equal(0m, s0.StartPartCount);
Assert.Null(s0.EndPartCount);
Assert.Null(s0.Quantity);
Assert.Equal(0, s0.IsSettled);
Assert.Null(s0.CloseReason);
Assert.Equal(default(DateTime), s0.CreatedAt);
Assert.Equal(default(DateTime), s0.UpdatedAt);
var s = new ProductionSegment
{
Id = 1,
MachineId = 2,
ProgramName = "Prog",
ProductionDate = new DateTime(2026, 4, 28),
StartTime = new DateTime(2026, 4, 28, 8, 0, 0),
EndTime = new DateTime(2026, 4, 28, 12, 0, 0),
StartPartCount = 10.0m,
EndPartCount = 20.0m,
Quantity = 10.0m,
IsSettled = 1,
CloseReason = "End",
CreatedAt = new DateTime(2026, 4, 28),
UpdatedAt = new DateTime(2026, 4, 29)
};
Assert.Equal(1, s.Id);
Assert.Equal(2, s.MachineId);
Assert.Equal("Prog", s.ProgramName);
Assert.Equal(new DateTime(2026, 4, 28), s.ProductionDate);
Assert.Equal(new DateTime(2026, 4, 28, 8, 0, 0), s.StartTime);
Assert.Equal(new DateTime(2026, 4, 28, 12, 0, 0), s.EndTime);
Assert.Equal(10.0m, s.StartPartCount);
Assert.Equal(20.0m, s.EndPartCount);
Assert.Equal(10.0m, s.Quantity);
Assert.Equal(1, s.IsSettled);
Assert.Equal("End", s.CloseReason);
Assert.Equal(new DateTime(2026, 4, 28), s.CreatedAt);
Assert.Equal(new DateTime(2026, 4, 29), s.UpdatedAt);
}
// MachineDailyStatus
[Fact]
public void MachineDailyStatus_DefaultsAndAssignments_ReturnsCorrectValues()
{
var m0 = new MachineDailyStatus();
Assert.Equal(0, m0.Id);
Assert.Equal(0, m0.MachineId);
Assert.Null(m0.DataStatus);
Assert.Equal(default(DateTime), m0.CreatedAt);
Assert.Equal(default(DateTime), m0.UpdatedAt);
var m = new MachineDailyStatus
{
Id = 5,
MachineId = 9,
ProductionDate = new DateTime(2026, 4, 28),
DataStatus = "Online",
CreatedAt = new DateTime(2026, 4, 28),
UpdatedAt = new DateTime(2026, 4, 29)
};
Assert.Equal(5, m.Id);
Assert.Equal(9, m.MachineId);
Assert.Equal("Online", m.DataStatus);
Assert.Equal(new DateTime(2026, 4, 28), m.ProductionDate);
Assert.Equal(new DateTime(2026, 4, 28), m.CreatedAt);
Assert.Equal(new DateTime(2026, 4, 29), m.UpdatedAt);
}
// DailyProduction
[Fact]
public void DailyProduction_DefaultsAndAssignments_ReturnsCorrectValues()
{
var d0 = new DailyProduction();
Assert.Equal(0, d0.Id);
Assert.Equal(0, d0.MachineId);
Assert.Equal(default(DateTime), d0.ProductionDate);
Assert.Null(d0.ProgramName);
Assert.Equal(0m, d0.TotalQuantity);
Assert.Equal(0, d0.SegmentCount);
Assert.Null(d0.TotalRunTime);
Assert.Null(d0.TotalCuttingTime);
Assert.Null(d0.TotalCycleTime);
Assert.Equal(0, d0.IsAdjusted);
Assert.Null(d0.AdjustedQuantity);
Assert.Equal(default(DateTime), d0.CreatedAt);
Assert.Equal(default(DateTime), d0.UpdatedAt);
var d = new DailyProduction
{
Id = 2,
MachineId = 3,
ProductionDate = new DateTime(2026, 4, 28),
ProgramName = "ProgA",
TotalQuantity = 100.5m,
SegmentCount = 5,
TotalRunTime = 3600.0m,
TotalCuttingTime = 1800.0m,
TotalCycleTime = 1200.0m,
IsAdjusted = 0,
AdjustedQuantity = 0.0m,
CreatedAt = new DateTime(2026, 4, 28),
UpdatedAt = new DateTime(2026, 4, 29)
};
Assert.Equal(2, d.Id);
Assert.Equal(3, d.MachineId);
Assert.Equal("ProgA", d.ProgramName);
Assert.Equal(new DateTime(2026, 4, 28), d.ProductionDate);
Assert.Equal(100.5m, d.TotalQuantity);
Assert.Equal(5, d.SegmentCount);
Assert.Equal(3600.0m, d.TotalRunTime);
Assert.Equal(1800.0m, d.TotalCuttingTime);
Assert.Equal(1200.0m, d.TotalCycleTime);
Assert.Equal(0, d.IsAdjusted);
Assert.Equal(new DateTime(2026, 4, 28), d.CreatedAt);
Assert.Equal(new DateTime(2026, 4, 29), d.UpdatedAt);
}
// WorkerDailySummary
[Fact]
public void WorkerDailySummary_DefaultsAndAssignments_ReturnsCorrectValues()
{
var w0 = new WorkerDailySummary();
Assert.Equal(0, w0.Id);
Assert.Equal(0, w0.WorkerId);
Assert.Equal(default(DateTime), w0.ProductionDate);
Assert.Equal(0m, w0.TotalQuantity);
Assert.Equal(0, w0.MachineCount);
Assert.Equal(0, w0.ProgramCount);
Assert.Equal(0, w0.IsAdjusted);
Assert.Null(w0.AdjustedQuantity);
Assert.Equal(default(DateTime), w0.CreatedAt);
Assert.Equal(default(DateTime), w0.UpdatedAt);
var w = new WorkerDailySummary
{
Id = 7,
WorkerId = 8,
ProductionDate = new DateTime(2026, 4, 28),
TotalQuantity = 45.0m,
MachineCount = 2,
ProgramCount = 3,
IsAdjusted = 1,
AdjustedQuantity = 44.5m,
CreatedAt = new DateTime(2026, 4, 28),
UpdatedAt = new DateTime(2026, 4, 29)
};
Assert.Equal(7, w.Id);
Assert.Equal(8, w.WorkerId);
Assert.Equal(new DateTime(2026, 4, 28), w.ProductionDate);
Assert.Equal(45.0m, w.TotalQuantity);
Assert.Equal(2, w.MachineCount);
Assert.Equal(3, w.ProgramCount);
Assert.Equal(1, w.IsAdjusted);
Assert.Equal(44.5m, w.AdjustedQuantity);
Assert.Equal(new DateTime(2026, 4, 28), w.CreatedAt);
Assert.Equal(new DateTime(2026, 4, 29), w.UpdatedAt);
}
// ProductionAdjustment
[Fact]
public void ProductionAdjustment_DefaultsAndAssignments_ReturnsCorrectValues()
{
var a0 = new ProductionAdjustment();
Assert.Equal(0L, a0.Id);
Assert.Null(a0.TargetTable);
Assert.Equal(0, a0.TargetId);
Assert.Null(a0.FieldName);
Assert.Null(a0.OldValue);
Assert.Equal(0m, a0.NewValue);
Assert.Null(a0.Reason);
Assert.Null(a0.OperatorIp);
Assert.Equal(default(DateTime), a0.CreatedAt);
var a = new ProductionAdjustment
{
Id = 1,
TargetTable = "cnc_daily_production",
TargetId = 2,
FieldName = "TotalQuantity",
OldValue = 10.0m,
NewValue = 12.5m,
Reason = "Adjustment",
OperatorIp = "127.0.0.1",
CreatedAt = new DateTime(2026, 4, 28)
};
Assert.Equal(1, a.Id);
Assert.Equal("cnc_daily_production", a.TargetTable);
Assert.Equal(2, a.TargetId);
Assert.Equal("TotalQuantity", a.FieldName);
Assert.Equal(10.0m, a.OldValue);
Assert.Equal(12.5m, a.NewValue);
Assert.Equal("Adjustment", a.Reason);
Assert.Equal("127.0.0.1", a.OperatorIp);
Assert.Equal(new DateTime(2026, 4, 28), a.CreatedAt);
}
// Alert
[Fact]
public void Alert_DefaultsAndAssignments_ReturnsCorrectValues()
{
var al0 = new Alert();
Assert.Equal(0L, al0.Id);
Assert.Null(al0.AlertType);
Assert.Null(al0.Title);
Assert.Null(al0.Detail);
Assert.Equal(0, al0.IsResolved);
Assert.Equal(default(DateTime), al0.CreatedAt);
Assert.Null(al0.ResolvedAt);
var al = new Alert
{
Id = 1,
AlertType = "Error",
MachineId = 5,
CollectAddressId = 6,
Title = "Alarm",
Detail = "Detail",
IsResolved = 1,
ResolvedAt = new DateTime(2026, 4, 28),
CreatedAt = new DateTime(2026, 4, 28)
};
Assert.Equal(1, al.Id);
Assert.Equal("Error", al.AlertType);
Assert.Equal(5, al.MachineId);
Assert.Equal(6, al.CollectAddressId);
Assert.Equal("Alarm", al.Title);
Assert.Equal("Detail", al.Detail);
Assert.Equal(1, al.IsResolved);
Assert.Equal(new DateTime(2026, 4, 28), al.ResolvedAt);
Assert.Equal(new DateTime(2026, 4, 28), al.CreatedAt);
}
// SysConfig
[Fact]
public void SysConfig_DefaultsAndAssignments_ReturnsCorrectValues()
{
var s0 = new SysConfig();
Assert.Equal(0, s0.Id);
Assert.Null(s0.ConfigKey);
Assert.Null(s0.ConfigValue);
Assert.Null(s0.ValueType);
Assert.Null(s0.Description);
Assert.Equal(default(DateTime), s0.UpdatedAt);
var s = new SysConfig
{
Id = 1,
ConfigKey = "MaxThreads",
ConfigValue = "4",
ValueType = "int",
Description = "最大线程数",
UpdatedAt = new DateTime(2026, 4, 29)
};
Assert.Equal(1, s.Id);
Assert.Equal("MaxThreads", s.ConfigKey);
Assert.Equal("4", s.ConfigValue);
Assert.Equal("int", s.ValueType);
Assert.Equal("最大线程数", s.Description);
Assert.Equal(new DateTime(2026, 4, 29), s.UpdatedAt);
}
// ScreenConfig
[Fact]
public void ScreenConfig_DefaultsAndAssignments_ReturnsCorrectValues()
{
var sc0 = new ScreenConfig();
Assert.Equal(0, sc0.Id);
Assert.Null(sc0.CardKey);
Assert.Null(sc0.ChartConfig);
Assert.Equal(default(DateTime), sc0.CreatedAt);
Assert.Equal(default(DateTime), sc0.UpdatedAt);
var sc = new ScreenConfig
{
Id = 2,
CardKey = "card-1",
CardType = "typeA",
Title = "Title",
Metric = "metric",
Dimension = "dim",
SortOrder = 1,
IsEnabled = 1,
ChartConfig = "{...}",
CreatedAt = new DateTime(2026, 4, 28),
UpdatedAt = new DateTime(2026, 4, 29)
};
Assert.Equal(2, sc.Id);
Assert.Equal("card-1", sc.CardKey);
Assert.Equal("typeA", sc.CardType);
Assert.Equal("Title", sc.Title);
Assert.Equal("metric", sc.Metric);
Assert.Equal("dim", sc.Dimension);
Assert.Equal(1, sc.SortOrder);
Assert.Equal(1, sc.IsEnabled);
Assert.Equal("{...}", sc.ChartConfig);
Assert.Equal(new DateTime(2026, 4, 28), sc.CreatedAt);
Assert.Equal(new DateTime(2026, 4, 29), sc.UpdatedAt);
}
// ScreenFilter
[Fact]
public void ScreenFilter_DefaultsAndAssignments_ReturnsCorrectValues()
{
var sf0 = new ScreenFilter();
Assert.Equal(0, sf0.Id);
Assert.Null(sf0.ScreenKey);
Assert.Null(sf0.FilterType);
Assert.Null(sf0.FilterValue);
Assert.Equal(0, sf0.IsDefault);
Assert.Equal(0, sf0.SortOrder);
var sf = new ScreenFilter
{
Id = 3,
ScreenKey = "key1",
FilterType = "type",
FilterValue = "value",
IsDefault = 1,
SortOrder = 2
};
Assert.Equal(3, sf.Id);
Assert.Equal("key1", sf.ScreenKey);
Assert.Equal("type", sf.FilterType);
Assert.Equal("value", sf.FilterValue);
Assert.Equal(1, sf.IsDefault);
Assert.Equal(2, sf.SortOrder);
}
// CollectRaw
[Fact]
public void CollectRaw_DefaultsAndAssignments_ReturnsCorrectValues()
{
var cr0 = new CollectRaw();
Assert.Equal(0L, cr0.Id);
Assert.Equal(0, cr0.CollectAddressId);
Assert.Equal(default(DateTime), cr0.RequestTime);
Assert.Equal(default(DateTime), cr0.ResponseTime);
Assert.Null(cr0.ResponseDuration);
Assert.Equal(0, cr0.IsSuccess);
Assert.Null(cr0.StatusCode);
Assert.Null(cr0.RawJson);
Assert.Null(cr0.ErrorMessage);
Assert.Equal(default(DateTime), cr0.CreatedAt);
var cr = new CollectRaw
{
Id = 1,
CollectAddressId = 2,
RequestTime = new DateTime(2026, 4, 28, 10, 0, 0),
ResponseTime = new DateTime(2026, 4, 28, 10, 0, 1),
ResponseDuration = 100,
IsSuccess = 1,
StatusCode = 200,
RawJson = "{\"a\":1}",
ErrorMessage = null,
CreatedAt = new DateTime(2026, 4, 28)
};
Assert.Equal(1, cr.Id);
Assert.Equal(2, cr.CollectAddressId);
Assert.Equal(new DateTime(2026, 4, 28, 10, 0, 0), cr.RequestTime);
Assert.Equal(new DateTime(2026, 4, 28, 10, 0, 1), cr.ResponseTime);
Assert.Equal(100, cr.ResponseDuration);
Assert.Equal(1, cr.IsSuccess);
Assert.Equal(200, cr.StatusCode);
Assert.Equal("{\"a\":1}", cr.RawJson);
Assert.Null(cr.ErrorMessage);
Assert.Equal(new DateTime(2026, 4, 28), cr.CreatedAt);
}
// SystemLog
[Fact]
public void SystemLog_DefaultsAndAssignments_ReturnsCorrectValues()
{
var sl0 = new SystemLog();
Assert.Equal(0L, sl0.Id);
Assert.Null(sl0.LogLevel);
Assert.Null(sl0.Source);
Assert.Null(sl0.Message);
Assert.Null(sl0.StackTrace);
Assert.Null(sl0.ExtraData);
Assert.Equal(default(DateTime), sl0.CreatedAt);
var sl = new SystemLog
{
Id = 9,
LogLevel = "Info",
Source = "SourceA",
Message = "msg",
StackTrace = "trace",
ExtraData = "{}",
CreatedAt = new DateTime(2026, 4, 28)
};
Assert.Equal(9, sl.Id);
Assert.Equal("Info", sl.LogLevel);
Assert.Equal("SourceA", sl.Source);
Assert.Equal("msg", sl.Message);
Assert.Equal("trace", sl.StackTrace);
Assert.Equal("{}", sl.ExtraData);
Assert.Equal(new DateTime(2026, 4, 28), sl.CreatedAt);
}
// CollectorHeartbeat
[Fact]
public void CollectorHeartbeat_DefaultsAndAssignments_ReturnsCorrectValues()
{
var cb0 = new CollectorHeartbeat();
Assert.Equal(0L, cb0.Id);
Assert.Null(cb0.ServiceId);
Assert.Null(cb0.Status);
Assert.Null(cb0.Detail);
Assert.Null(cb0.LastCollectTime);
Assert.Equal(0, cb0.SuccessCount);
Assert.Equal(0, cb0.FailCount);
Assert.Null(cb0.UptimeSeconds);
Assert.Equal(default(DateTime), cb0.CreatedAt);
var cb = new CollectorHeartbeat
{
Id = 11,
ServiceId = "svc-1",
Status = "Healthy",
CollectAddressId = 4,
LastCollectTime = new DateTime(2026, 4, 28, 12, 0, 0),
SuccessCount = 10,
FailCount = 1,
UptimeSeconds = 3600,
Detail = "{}",
CreatedAt = new DateTime(2026, 4, 28)
};
Assert.Equal(11, cb.Id);
Assert.Equal("svc-1", cb.ServiceId);
Assert.Equal("Healthy", cb.Status);
Assert.Equal(4, cb.CollectAddressId);
Assert.Equal(new DateTime(2026, 4, 28, 12, 0, 0), cb.LastCollectTime);
Assert.Equal(10, cb.SuccessCount);
Assert.Equal(1, cb.FailCount);
Assert.Equal(3600, cb.UptimeSeconds);
Assert.Equal("{}", cb.Detail);
Assert.Equal(new DateTime(2026, 4, 28), cb.CreatedAt);
}
// Machine
[Fact]
public void Machine_DefaultsAndAssignments_ReturnsCorrectValues()
{
var m0 = new Machine();
Assert.Equal(0, m0.Id);
Assert.Null(m0.DeviceCode);
Assert.Null(m0.Name);
Assert.Equal(0, m0.WorkshopId);
Assert.Equal(0, m0.CollectAddressId);
Assert.Null(m0.IpAddress);
Assert.Equal(0, m0.BrandId);
Assert.Equal(0, m0.IsEnabled);
Assert.Equal(0, m0.IsOnline);
Assert.Null(m0.LastPingTime);
Assert.Null(m0.LastCollectTime);
Assert.Null(m0.LastDeviceStatus);
Assert.Null(m0.LastRunStatus);
Assert.Null(m0.LastProgramName);
Assert.Null(m0.LastPartCount);
Assert.Null(m0.LastOperateMode);
Assert.Null(m0.LastMachiningStatus);
Assert.Equal(default(DateTime), m0.CreatedAt);
Assert.Equal(default(DateTime), m0.UpdatedAt);
var m = new Machine
{
Id = 10,
DeviceCode = "M-10",
Name = "Machine10",
WorkshopId = 1,
CollectAddressId = 2,
IpAddress = "192.168.0.10",
BrandId = 3,
IsEnabled = 1,
IsOnline = 1,
LastPingTime = new DateTime(2026, 4, 28, 12, 0, 0),
LastCollectTime = new DateTime(2026, 4, 28, 12, 5, 0),
LastDeviceStatus = "OK",
LastRunStatus = "Running",
LastProgramName = "Prog1",
LastPartCount = 42.0m,
LastOperateMode = "Auto",
LastMachiningStatus = "Active",
CreatedAt = new DateTime(2026, 4, 28),
UpdatedAt = new DateTime(2026, 4, 29)
};
Assert.Equal(10, m.Id);
Assert.Equal("M-10", m.DeviceCode);
Assert.Equal("Machine10", m.Name);
Assert.Equal(1, m.WorkshopId);
Assert.Equal(2, m.CollectAddressId);
Assert.Equal("192.168.0.10", m.IpAddress);
Assert.Equal(3, m.BrandId);
Assert.Equal(1, m.IsEnabled);
Assert.Equal(1, m.IsOnline);
Assert.Equal(new DateTime(2026, 4, 28, 12, 0, 0), m.LastPingTime);
Assert.Equal(new DateTime(2026, 4, 28, 12, 5, 0), m.LastCollectTime);
Assert.Equal("OK", m.LastDeviceStatus);
Assert.Equal("Running", m.LastRunStatus);
Assert.Equal("Prog1", m.LastProgramName);
Assert.Equal(42.0m, m.LastPartCount);
Assert.Equal("Auto", m.LastOperateMode);
Assert.Equal("Active", m.LastMachiningStatus);
Assert.Equal(new DateTime(2026, 4, 28), m.CreatedAt);
Assert.Equal(new DateTime(2026, 4, 29), m.UpdatedAt);
}
// Worker
[Fact]
public void Worker_DefaultsAndAssignments_ReturnsCorrectValues()
{
var w0 = new Worker();
Assert.Equal(0, w0.Id);
Assert.Null(w0.Name);
Assert.Null(w0.Code);
Assert.Equal(0, w0.IsEnabled);
Assert.Equal(default(DateTime), w0.CreatedAt);
Assert.Equal(default(DateTime), w0.UpdatedAt);
var w = new Worker
{
Id = 2,
Name = "张三",
Code = "W-2",
IsEnabled = 1,
CreatedAt = new DateTime(2026, 4, 28),
UpdatedAt = new DateTime(2026, 4, 29)
};
Assert.Equal(2, w.Id);
Assert.Equal("张三", w.Name);
Assert.Equal("W-2", w.Code);
Assert.Equal(1, w.IsEnabled);
Assert.Equal(new DateTime(2026, 4, 28), w.CreatedAt);
Assert.Equal(new DateTime(2026, 4, 29), w.UpdatedAt);
}
// WorkerMachine
[Fact]
public void WorkerMachine_DefaultsAndAssignments_ReturnsCorrectValues()
{
var wm0 = new WorkerMachine();
Assert.Equal(0, wm0.Id);
Assert.Equal(0, wm0.WorkerId);
Assert.Equal(0, wm0.MachineId);
Assert.Equal(default(DateTime), wm0.CreatedAt);
var wm = new WorkerMachine
{
Id = 1,
WorkerId = 2,
MachineId = 3,
CreatedAt = new DateTime(2026, 4, 28)
};
Assert.Equal(1, wm.Id);
Assert.Equal(2, wm.WorkerId);
Assert.Equal(3, wm.MachineId);
Assert.Equal(new DateTime(2026, 4, 28), wm.CreatedAt);
}
}
}

@ -0,0 +1,83 @@
using System;
using System.Reflection;
using System.Text;
using Xunit;
using CncModels.Enum;
namespace CncModels.Tests
{
/// <summary>
/// 测试所有 CncModels.Enum 下的字符串常量,确保值与命名约定一致。
/// 约定:字段名转换为 snake_case 小写字符串后应当与常量值一致。
/// 例如 AlertType.CollectFail 应为 "collect_fail"。
/// </summary>
public class EnumTests
{
/// <summary>
/// 遍历除 LogLevel 外的所有枚举类,验证 snake_case 命名约定
/// 覆盖场景AlertType/CollectStatus/DataStatus/CardType/DataType/MatchBy/SegmentCloseReason/CollectorServiceStatus/ValueType
/// </summary>
[Fact]
public void SnakeCaseEnums_ShouldMatchFieldNames()
{
Type[] snakeCaseEnums = new Type[]
{
typeof(AlertType),
typeof(CollectStatus),
typeof(DataStatus),
typeof(CardType),
typeof(DataType),
typeof(MatchBy),
typeof(SegmentCloseReason),
typeof(CollectorServiceStatus),
typeof(CncModels.Enum.ValueType)
};
foreach (var t in snakeCaseEnums)
{
var fields = t.GetFields(BindingFlags.Public | BindingFlags.Static);
Assert.True(fields.Length > 0, $"类型 {t.Name} 不包含公共静态字段。");
foreach (var f in fields)
{
if (f.FieldType != typeof(string)) continue;
string value = (string)f.GetValue(null);
string expected = ToSnakeCase(f.Name);
Assert.Equal(expected, value);
}
}
}
/// <summary>
/// 验证 LogLevel 枚举值为大写(数据库中 log_level 存储为大写)
/// 覆盖场景DEBUG/INFO/WARN/ERROR 全部值
/// </summary>
[Fact]
public void LogLevel_ShouldBeUppercase()
{
Assert.Equal("DEBUG", LogLevel.Debug);
Assert.Equal("INFO", LogLevel.Info);
Assert.Equal("WARN", LogLevel.Warn);
Assert.Equal("ERROR", LogLevel.Error);
}
private string ToSnakeCase(string input)
{
if (string.IsNullOrEmpty(input)) return input;
var sb = new StringBuilder();
for (int i = 0; i < input.Length; i++)
{
char c = input[i];
if (char.IsUpper(c))
{
if (i > 0) sb.Append('_');
sb.Append(char.ToLowerInvariant(c));
}
else
{
sb.Append(c);
}
}
return sb.ToString();
}
}
}

@ -0,0 +1,103 @@
using System;
using Xunit;
using CncModels.Dto;
using CncModels.Dto.Login;
using CncModels.Dto.Machine;
namespace CncModels.Tests
{
/// <summary>
/// PagedQuery 单元测试:覆盖默认值、偏移计算与自动修正逻辑
/// </summary>
public class PagedQueryTests
{
[Fact]
/// <summary>
/// 默认值正确page=1, pageSize=20, offset=0
/// </summary>
public void Page_Defaults_Are_Correct()
{
// Arrange/Act
var q = new PagedQuery();
// Assert
Assert.Equal(1, q.Page);
Assert.Equal(20, q.PageSize);
Assert.Equal(0, q.Offset);
}
[Fact]
/// <summary>
/// 标准赋值Page=3, PageSize=10 -> Offset=20
/// </summary>
public void Page_And_PageSize_Normal_Assignments()
{
// Arrange
var q = new PagedQuery
{
Page = 3,
PageSize = 10
};
// Assert
Assert.Equal(3, q.Page);
Assert.Equal(10, q.PageSize);
Assert.Equal(20, q.Offset);
}
[Fact]
/// <summary>
/// 边界Page=100, PageSize=20
/// </summary>
public void Page_Boundary_Normal()
{
var q = new PagedQuery { Page = 100, PageSize = 20 };
Assert.Equal(100, q.Page);
Assert.Equal(20, q.PageSize);
Assert.Equal(1980, q.Offset);
}
[Fact]
/// <summary>
/// 自动修正Page=0 -> 1
/// </summary>
public void Page_AutoFix_When_Zero()
{
var q = new PagedQuery { Page = 0 };
Assert.Equal(1, q.Page);
}
[Fact]
/// <summary>
/// 自动修正Page=-5 -> 1
/// </summary>
public void Page_AutoFix_When_Negative()
{
var q = new PagedQuery { Page = -5 };
Assert.Equal(1, q.Page);
}
[Fact]
/// <summary>
/// 自动修正PageSize=0 -> 20
/// </summary>
public void PageSize_AutoFix_When_Zero()
{
var q = new PagedQuery { PageSize = 0 };
Assert.Equal(20, q.PageSize);
}
[Fact]
/// <summary>
/// 自动修正PageSize=101 -> 100
/// </summary>
public void PageSize_AutoFix_When_Over_Max()
{
var q1 = new PagedQuery { PageSize = 101 };
Assert.Equal(100, q1.PageSize);
var q2 = new PagedQuery { PageSize = 999 };
Assert.Equal(100, q2.PageSize);
}
}
}

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using Xunit;
using CncModels.Dto;
namespace CncModels.Tests
{
/// <summary>
/// PagedResult<T> 单元测试
/// </summary>
public class PagedResultTests
{
[Theory]
[InlineData(20, 20, 1)]
[InlineData(21, 20, 2)]
[InlineData(0, 10, 0)]
public void TotalPages_Calculation_Works(int total, int pageSize, int expectedPages)
{
// Arrange
var r = new PagedResult<string>
{
Total = total,
PageSize = pageSize,
Page = 1
};
// Act & Assert
Assert.Equal(expectedPages, r.TotalPages);
}
[Fact]
/// <summary>
/// Items 属性默认应为空列表而非 null
/// </summary>
public void Items_Should_Be_Empty_List_By_Default()
{
// Arrange
var r = new PagedResult<string>();
// Assert
Assert.NotNull(r.Items);
Assert.Empty(r.Items);
}
[Fact]
/// <summary>
/// 属性赋值正确
/// </summary>
public void Properties_Assigned_Correctly()
{
// Arrange
var items = new List<string> { "a", "b" };
var r = new PagedResult<string>
{
Items = items,
Total = 2,
Page = 1,
PageSize = 2
};
// Assert
Assert.Equal(items, r.Items);
Assert.Equal(2, r.Total);
Assert.Equal(1, r.Page);
Assert.Equal(2, r.PageSize);
Assert.Equal(1, r.TotalPages); // 2/2 = 1
}
}
}
Loading…
Cancel
Save