using System;
using Xunit;
using CncCollector.Core;
namespace CncCollector.Tests
{
///
/// ProductionTracker 单元测试。
/// ProductionTracker 直接使用 MySqlConnection,无法通过 Moq 注入,
/// 因此使用无效连接字符串验证容错行为(不抛异常)。
///
public class ProductionTrackerTests : IDisposable
{
/// 无效连接字符串,用于触发错误处理路径
private const string InvalidConnStr = "Server=invalid;Database=invalid;User Id=invalid;Password=invalid;";
private ProductionTracker _tracker;
public ProductionTrackerTests()
{
_tracker = new ProductionTracker(InvalidConnStr);
}
public void Dispose()
{
_tracker?.Dispose();
}
// ===== 构造函数测试 =====
[Fact]
public void 构造函数_正常创建()
{
var tracker = new ProductionTracker(InvalidConnStr);
Assert.NotNull(tracker);
}
[Fact]
public void 构造函数_null连接字符串_正常创建()
{
// 构造函数本身不做连接验证,允许 null
var tracker = new ProductionTracker(null);
Assert.NotNull(tracker);
}
// ===== Track 方法测试 =====
[Fact]
public void Track_无效DB连接_不抛异常()
{
// 使用无效连接字符串调用 Track,内部 DB 操作会失败但不应该向外抛出异常
var ex = Record.Exception(() => _tracker.Track(1, "O0001", 100m, DateTime.Now));
Assert.Null(ex);
}
[Fact]
public void Track_空程序名_不抛异常()
{
// programName 为空时应提前返回,不做任何 DB 操作
var ex = Record.Exception(() => _tracker.Track(1, "", 100m, DateTime.Now));
Assert.Null(ex);
}
[Fact]
public void Track_null程序名_不抛异常()
{
var ex = Record.Exception(() => _tracker.Track(1, null, 100m, DateTime.Now));
Assert.Null(ex);
}
[Fact]
public void Track_partCount为null_不抛异常()
{
var ex = Record.Exception(() => _tracker.Track(1, "O0001", null, DateTime.Now));
Assert.Null(ex);
}
[Fact]
public void Track_连续调用不同程序_不抛异常()
{
// 模拟程序切换场景
var ex1 = Record.Exception(() => _tracker.Track(1, "O0001", 10m, DateTime.Now));
Assert.Null(ex1);
var ex2 = Record.Exception(() => _tracker.Track(1, "O0002", 5m, DateTime.Now));
Assert.Null(ex2);
}
[Fact]
public void Track_零件数下降_不抛异常()
{
// 模拟手动清零场景:同程序下 partCount 下降
var ex1 = Record.Exception(() => _tracker.Track(1, "O0001", 100m, DateTime.Now));
Assert.Null(ex1);
var ex2 = Record.Exception(() => _tracker.Track(1, "O0001", 5m, DateTime.Now));
Assert.Null(ex2);
}
[Fact]
public void Track_多台机床并行_不抛异常()
{
var ex1 = Record.Exception(() => _tracker.Track(1, "O0001", 10m, DateTime.Now));
Assert.Null(ex1);
var ex2 = Record.Exception(() => _tracker.Track(2, "O0002", 20m, DateTime.Now));
Assert.Null(ex2);
var ex3 = Record.Exception(() => _tracker.Track(3, "O0003", 30m, DateTime.Now));
Assert.Null(ex3);
}
// ===== CloseActiveSegment 测试 =====
[Fact]
public void CloseActiveSegment_无活跃段_不抛异常()
{
var ex = Record.Exception(() => _tracker.CloseActiveSegment(999, 100m, "program_change", DateTime.Now));
Assert.Null(ex);
}
[Fact]
public void CloseActiveSegment_null参数_不抛异常()
{
var ex = Record.Exception(() => _tracker.CloseActiveSegment(1, null, "manual_reset", DateTime.Now));
Assert.Null(ex);
}
// ===== CloseAllActiveSegments 测试 =====
[Fact]
public void CloseAllActiveSegments_无活跃段_不抛异常()
{
var ex = Record.Exception(() => _tracker.CloseAllActiveSegments());
Assert.Null(ex);
}
[Fact]
public void CloseAllActiveSegments_有Track记录_不抛异常()
{
// 先 Track 产生内存缓存,再 CloseAll
_tracker.Track(1, "O0001", 10m, DateTime.Now);
var ex = Record.Exception(() => _tracker.CloseAllActiveSegments());
Assert.Null(ex);
}
// ===== Dispose 测试 =====
[Fact]
public void Dispose_正常调用_不抛异常()
{
var tracker = new ProductionTracker(InvalidConnStr);
var ex = Record.Exception(() => tracker.Dispose());
Assert.Null(ex);
}
[Fact]
public void Dispose_多次调用_不抛异常()
{
var tracker = new ProductionTracker(InvalidConnStr);
tracker.Dispose();
tracker.Dispose(); // 二次调用不应抛异常
}
}
}