using System; using System.Threading; using Xunit; using CncCollector.Core; using CncCollector.Config; using CncModels.Entity; using Moq; // 测试项目常用依赖,当前测试未直接使用 Mock,但保留以匹配项目风格 namespace CncCollector.Tests { /// /// CollectWorker 的单元测试集合(针对构造与基本控制流程)。 /// 使用无效的数据库连接和无效的 HTTP 地址,确保线程启动/停止的行为在异常情况下也能健壮执行。 /// public class CollectWorkerTests : IDisposable { private CollectWorker _worker; private CollectAddress _address; private CollectorConfig _config; /// /// 创建一个 CollectWorker 实例,方便各测试用例复用。 /// 注:为了测试稳定性,数据库连接字符串与 URL 使用无效值。 /// private void CreateWorker() { _address = new CollectAddress { Id = 1, Name = "TestAddress", Url = "http://invalid.localhost/health", // 无效地址,避免真实网络请求 BrandId = 1, CollectInterval = 1 // 1 秒间隔,便于测试快速循环 }; _config = new CollectorConfig(); // 无效连接字符串,确保不会真正连接到数据库 string businessConn = "Server=.;Database=NonExistingDb;User Id=invalid;Password=invalid;"; string logConn = "Server=.;Database=NonExistingLogDb;User Id=invalid;Password=invalid;"; // 允许 tracker 为 null,因为在无效 URL 的测试路径下通常不会进入需要 Tracker 的分支 _worker = new CollectWorker(_address, _config, null, businessConn, logConn); } public void Dispose() { if (_worker != null) { try { _worker.Stop(); } catch { /* 忽略停止时的异常,确保测试清理安全 */ } } } /// /// 构造函数_正常创建_属性正确 /// 验证 AddressId, AddressName, IsRunning, LastCollectTime, SuccessCount, FailCount /// [Fact] public void 构造函数_正常创建_属性正确() { CreateWorker(); Assert.Equal(1, _worker.AddressId); Assert.Equal("TestAddress", _worker.AddressName); Assert.False(_worker.IsRunning); Assert.Null(_worker.LastCollectTime); Assert.Equal(0L, _worker.SuccessCount); Assert.Equal(0L, _worker.FailCount); } /// /// IsRunning_初始值_false /// [Fact] public void IsRunning_初始值_false() { CreateWorker(); Assert.False(_worker.IsRunning); } /// /// LastCollectTime_初始值_null /// [Fact] public void LastCollectTime_初始值_null() { CreateWorker(); Assert.Null(_worker.LastCollectTime); } /// /// SuccessCount_初始值_0 /// [Fact] public void SuccessCount_初始值_0() { CreateWorker(); Assert.Equal(0L, _worker.SuccessCount); } /// /// FailCount_初始值_0 /// [Fact] public void FailCount_初始值_0() { CreateWorker(); Assert.Equal(0L, _worker.FailCount); } /// /// Start_调用后_IsRunning变true /// 注:Start 会启动后台线程,测试后需要 Stop /// [Fact] public void Start_调用后_IsRunning变true() { CreateWorker(); _worker.Start(); // 给予一点时间让后台线程启动 Thread.Sleep(200); Assert.True(_worker.IsRunning); _worker.Stop(); Thread.Sleep(100); Assert.False(_worker.IsRunning); } /// /// Stop_调用后_IsRunning变false /// [Fact] public void Stop_调用后_IsRunning变false() { CreateWorker(); _worker.Stop(); Assert.False(_worker.IsRunning); } /// /// Start_调用两次_不崩溃 /// [Fact] public void Start_调用两次_不崩溃() { CreateWorker(); _worker.Start(); Thread.Sleep(100); // 再次调用 Start,应该不抛出异常 _worker.Start(); _worker.Stop(); Thread.Sleep(100); Assert.False(_worker.IsRunning); } /// /// Stop_未启动就调用_不崩溃 /// [Fact] public void Stop_未启动就调用_不崩溃() { CreateWorker(); // 直接停止,未启动状态也应稳定 _worker.Stop(); _worker.Stop(); Assert.False(_worker.IsRunning); } } }