388 lines
20 KiB
C#
388 lines
20 KiB
C#
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||
using ThreatSource.Utils;
|
||
using ThreatSource.Equipment;
|
||
|
||
namespace ThreatSource.Tests
|
||
{
|
||
[TestClass]
|
||
public class SwerlingRcsModelTests
|
||
{
|
||
private const double DefaultAverageRcs = 10.0; // 默认平均RCS值,单位:平方米
|
||
private const string TargetId1 = "target_tank_001"; // 测试用目标ID 1
|
||
private const string TargetId2 = "target_heli_002"; // 测试用目标ID 2
|
||
private const int TestSeed = 12345; // 测试用随机数种子
|
||
|
||
/// <summary>
|
||
/// 测试:默认构造函数应成功初始化。
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void Constructor_DefaultSeed_InitializesSuccessfully()
|
||
{
|
||
// 准备 (Arrange)
|
||
SwerlingRcsModel model;
|
||
|
||
// 操作 (Act)
|
||
model = new SwerlingRcsModel();
|
||
|
||
// 断言 (Assert)
|
||
Assert.IsNotNull(model, "使用默认种子构造模型实例不应为null。");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:带特定种子的构造函数应成功初始化。
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void Constructor_WithSpecificSeed_InitializesSuccessfully()
|
||
{
|
||
// 准备 (Arrange)
|
||
SwerlingRcsModel model;
|
||
|
||
// 操作 (Act)
|
||
model = new SwerlingRcsModel(TestSeed);
|
||
|
||
// 断言 (Assert)
|
||
Assert.IsNotNull(model, "使用特定种子构造模型实例不应为null。");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:当目标是坦克且静止时,其RCS行为应类似Swerling I (慢起伏,使用缓存)。
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void GetRealtimeRcs_Tank_Static_BehavesAsSwerlingI()
|
||
{
|
||
// 准备 (Arrange)
|
||
var model = new SwerlingRcsModel(TestSeed);
|
||
|
||
// 操作 (Act)
|
||
// 第一次调用,isNewScanPeriod为false但由于是首次,应采样并缓存
|
||
double rcs1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
|
||
// 第二次调用,isNewScanPeriod为false,应从缓存获取
|
||
double rcs2 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
|
||
|
||
// 断言 (Assert)
|
||
Assert.AreEqual(rcs1, rcs2, "对于Swerling I模型 (Tank, Static),在同一扫描周期内(isNewScanPeriod=false),RCS值应从缓存读取且保持不变。");
|
||
Assert.IsTrue(rcs1 > 0, "RCS值应大于0。");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:当目标是直升机且静止时,其RCS行为应类似Swerling II (快起伏,不使用缓存)。
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void GetRealtimeRcs_Helicopter_Static_BehavesAsSwerlingII()
|
||
{
|
||
// 准备 (Arrange)
|
||
var model = new SwerlingRcsModel(TestSeed);
|
||
|
||
// 操作 (Act)
|
||
double rcs1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Helicopter, MotionStateType.Static, DefaultAverageRcs, false);
|
||
double rcs2 = model.GetRealtimeRcs(TargetId1, EquipmentType.Helicopter, MotionStateType.Static, DefaultAverageRcs, false);
|
||
|
||
// 断言 (Assert)
|
||
// 对于快起伏,即使ID相同,种子固定情况下,连续调用也应基于随机数序列产生可预测的不同值
|
||
// 注意:这里比较的是"不同",但因为种子固定,这两个值本身是确定的。
|
||
// 如果需要严格验证"不同",可以比较两者差的绝对值大于某个小量,但更简单的做法是验证它们不相等。
|
||
Assert.AreNotEqual(rcs1, rcs2, "对于Swerling II模型 (Helicopter, Static),连续调用RCS值理论上应不同(因为是快起伏,每次都重新采样)。");
|
||
Assert.IsTrue(rcs1 > 0, "第一个RCS值应大于0。");
|
||
Assert.IsTrue(rcs2 > 0, "第二个RCS值应大于0。");
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 测试:当目标是坦克且机动时,其RCS行为应类似Swerling III (慢起伏,使用缓存)。
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void GetRealtimeRcs_Tank_Maneuvering_BehavesAsSwerlingIII()
|
||
{
|
||
// 准备 (Arrange)
|
||
var model = new SwerlingRcsModel(TestSeed);
|
||
|
||
// 操作 (Act)
|
||
double rcs1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Maneuvering, DefaultAverageRcs, false);
|
||
double rcs2 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Maneuvering, DefaultAverageRcs, false);
|
||
|
||
// 断言 (Assert)
|
||
Assert.AreEqual(rcs1, rcs2, "对于Swerling III模型 (Tank, Maneuvering),在同一扫描周期内,RCS值应从缓存读取且保持不变。");
|
||
Assert.IsTrue(rcs1 > 0, "RCS值应大于0。");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:当目标是直升机且机动时,其RCS行为应类似Swerling IV (快起伏,不使用缓存)。
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void GetRealtimeRcs_Helicopter_Maneuvering_BehavesAsSwerlingIV()
|
||
{
|
||
// 准备 (Arrange)
|
||
var model = new SwerlingRcsModel(TestSeed);
|
||
|
||
// 操作 (Act)
|
||
double rcs1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Helicopter, MotionStateType.Maneuvering, DefaultAverageRcs, false);
|
||
double rcs2 = model.GetRealtimeRcs(TargetId1, EquipmentType.Helicopter, MotionStateType.Maneuvering, DefaultAverageRcs, false);
|
||
|
||
// 断言 (Assert)
|
||
Assert.AreNotEqual(rcs1, rcs2, "对于Swerling IV模型 (Helicopter, Maneuvering),连续调用RCS值应不同。");
|
||
Assert.IsTrue(rcs1 > 0, "第一个RCS值应大于0。");
|
||
Assert.IsTrue(rcs2 > 0, "第二个RCS值应大于0。");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:当目标是坦克且匀速运动时,其RCS行为应类似Swerling I (慢起伏,使用缓存)。
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void GetRealtimeRcs_Tank_ConstantVelocity_BehavesAsSwerlingI()
|
||
{
|
||
// 准备 (Arrange)
|
||
var model = new SwerlingRcsModel(TestSeed);
|
||
|
||
// 操作 (Act)
|
||
double rcs1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.ConstantVelocity, DefaultAverageRcs, false);
|
||
double rcs2 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.ConstantVelocity, DefaultAverageRcs, false);
|
||
|
||
// 断言 (Assert)
|
||
Assert.AreEqual(rcs1, rcs2, "对于Swerling I模型 (Tank, ConstantVelocity),在同一扫描周期内,RCS值应从缓存读取且保持不变。");
|
||
Assert.IsTrue(rcs1 > 0, "RCS值应大于0。");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:当目标是直升机且匀速运动时,其RCS行为应类似Swerling II (快起伏,不使用缓存)。
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void GetRealtimeRcs_Helicopter_ConstantVelocity_BehavesAsSwerlingII()
|
||
{
|
||
// 准备 (Arrange)
|
||
var model = new SwerlingRcsModel(TestSeed);
|
||
|
||
// 操作 (Act)
|
||
double rcs1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Helicopter, MotionStateType.ConstantVelocity, DefaultAverageRcs, false);
|
||
double rcs2 = model.GetRealtimeRcs(TargetId1, EquipmentType.Helicopter, MotionStateType.ConstantVelocity, DefaultAverageRcs, false);
|
||
|
||
// 断言 (Assert)
|
||
Assert.AreNotEqual(rcs1, rcs2, "对于Swerling II模型 (Helicopter, ConstantVelocity),连续调用RCS值应不同。");
|
||
Assert.IsTrue(rcs1 > 0, "第一个RCS值应大于0。");
|
||
Assert.IsTrue(rcs2 > 0, "第二个RCS值应大于0。");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:当目标类型未知时,应默认为Swerling I行为。
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void GetRealtimeRcs_UnknownEquipment_BehavesAsSwerlingI()
|
||
{
|
||
// 准备 (Arrange)
|
||
var model = new SwerlingRcsModel(TestSeed);
|
||
|
||
// 操作 (Act)
|
||
double rcs1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Unknown, MotionStateType.Static, DefaultAverageRcs, false);
|
||
double rcs2 = model.GetRealtimeRcs(TargetId1, EquipmentType.Unknown, MotionStateType.Static, DefaultAverageRcs, false);
|
||
|
||
// 断言 (Assert)
|
||
Assert.AreEqual(rcs1, rcs2, "对于未知装备类型,应默认为Swerling I行为,RCS值在同一扫描周期内应保持不变。");
|
||
Assert.IsTrue(rcs1 > 0, "RCS值应大于0。");
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 测试:慢起伏模型在同一扫描周期内(isNewScanPeriod=false)应返回缓存的RCS值。
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void GetRealtimeRcs_SlowFluctuation_SameScanPeriod_ReturnsCachedValue()
|
||
{
|
||
// 准备 (Arrange)
|
||
var model = new SwerlingRcsModel(TestSeed);
|
||
// 首次调用,isNewScanPeriod 为 true 或 false 都会导致采样和缓存 (对于Swerling I)
|
||
double initialRcs = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, true);
|
||
|
||
// 操作 (Act)
|
||
// 后续调用,isNewScanPeriod 为 false
|
||
double cachedRcs = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
|
||
|
||
// 断言 (Assert)
|
||
Assert.AreEqual(initialRcs, cachedRcs, "慢起伏模型在同一扫描周期内应返回相同的缓存RCS值。");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:慢起伏模型在新扫描周期开始时(isNewScanPeriod=true)应更新并返回新的缓存RCS值。
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void GetRealtimeRcs_SlowFluctuation_NewScanPeriod_UpdatesAndReturnsNewCachedValue()
|
||
{
|
||
// 准备 (Arrange)
|
||
var model = new SwerlingRcsModel(TestSeed); // 使用固定种子
|
||
double rcsScan1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
|
||
|
||
// 操作 (Act)
|
||
// 新扫描周期开始
|
||
double rcsScan2PeriodStart = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, true);
|
||
// 在新扫描周期内再次获取,应与周期开始时相同
|
||
double rcsScan2SamePeriod = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
|
||
|
||
// 断言 (Assert)
|
||
// 由于种子固定,rcsScan1 和 rcsScan2PeriodStart 应该不同(因为重新采样了)
|
||
// 但对于不同的随机数序列,它们也可能偶然相同,所以这个断言不是绝对的,更多的是检查行为
|
||
// 更可靠的测试是验证 rcsScan2PeriodStart 和 rcsScan2SamePeriod 相同
|
||
Assert.AreNotEqual(rcsScan1, rcsScan2PeriodStart, "新扫描周期开始时,RCS值应重新采样,与旧周期的值不同(高概率)。");
|
||
Assert.AreEqual(rcsScan2PeriodStart, rcsScan2SamePeriod, "在新扫描周期内,后续获取的RCS值应与周期开始时采样并缓存的值相同。");
|
||
Assert.IsTrue(rcsScan1 > 0, "第一个扫描周期的RCS值应大于0。");
|
||
Assert.IsTrue(rcsScan2PeriodStart > 0, "第二个扫描周期开始的RCS值应大于0。");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:当平均RCS为0时,GetRealtimeRcs应返回0。
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void GetRealtimeRcs_AverageRcsZero_ReturnsZero()
|
||
{
|
||
// 准备 (Arrange)
|
||
var model = new SwerlingRcsModel();
|
||
|
||
// 操作 (Act)
|
||
double rcsS1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, 0.0, false);
|
||
double rcsS2 = model.GetRealtimeRcs(TargetId1, EquipmentType.Helicopter, MotionStateType.Static, 0.0, false);
|
||
double rcsS3 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Maneuvering, 0.0, false);
|
||
double rcsS4 = model.GetRealtimeRcs(TargetId1, EquipmentType.Helicopter, MotionStateType.Maneuvering, 0.0, false);
|
||
|
||
// 断言 (Assert)
|
||
Assert.AreEqual(0.0, rcsS1, "Swerling I,平均RCS为0时,应返回0。");
|
||
Assert.AreEqual(0.0, rcsS2, "Swerling II,平均RCS为0时,应返回0。");
|
||
Assert.AreEqual(0.0, rcsS3, "Swerling III,平均RCS为0时,应返回0。");
|
||
Assert.AreEqual(0.0, rcsS4, "Swerling IV,平均RCS为0时,应返回0。");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:当平均RCS为负数时,GetRealtimeRcs应返回0。
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void GetRealtimeRcs_AverageRcsNegative_ReturnsZero()
|
||
{
|
||
// 准备 (Arrange)
|
||
var model = new SwerlingRcsModel();
|
||
|
||
// 操作 (Act)
|
||
double rcs = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, -5.0, false);
|
||
|
||
// 断言 (Assert)
|
||
Assert.AreEqual(0.0, rcs, "平均RCS为负数时,应返回0。");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:对于Swerling I模型,如果targetId为null,应抛出ArgumentNullException。
|
||
/// </summary>
|
||
[TestMethod]
|
||
[ExpectedException(typeof(ArgumentNullException))]
|
||
public void GetRealtimeRcs_SwerlingI_NullTargetId_ThrowsArgumentNullException()
|
||
{
|
||
// 准备 (Arrange)
|
||
var model = new SwerlingRcsModel();
|
||
|
||
// 操作 (Act)
|
||
model.GetRealtimeRcs(null!, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:对于Swerling I模型,如果targetId为空字符串,应抛出ArgumentNullException。
|
||
/// </summary>
|
||
[TestMethod]
|
||
[ExpectedException(typeof(ArgumentNullException))]
|
||
public void GetRealtimeRcs_SwerlingI_EmptyTargetId_ThrowsArgumentNullException()
|
||
{
|
||
// 准备 (Arrange)
|
||
var model = new SwerlingRcsModel();
|
||
|
||
// 操作 (Act)
|
||
model.GetRealtimeRcs(string.Empty, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:对于Swerling III模型,如果targetId为null,应抛出ArgumentNullException。
|
||
/// </summary>
|
||
[TestMethod]
|
||
[ExpectedException(typeof(ArgumentNullException))]
|
||
public void GetRealtimeRcs_SwerlingIII_NullTargetId_ThrowsArgumentNullException()
|
||
{
|
||
// 准备 (Arrange)
|
||
var model = new SwerlingRcsModel();
|
||
|
||
// 操作 (Act)
|
||
model.GetRealtimeRcs(null!, EquipmentType.Tank, MotionStateType.Maneuvering, DefaultAverageRcs, false);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 测试:ClearCachedRcs应清除特定目标的缓存,导致下次调用重新采样。
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void ClearCachedRcs_SlowFluctuation_ForcesNewSampleForSpecificTarget()
|
||
{
|
||
// 准备 (Arrange)
|
||
var model = new SwerlingRcsModel(TestSeed);
|
||
double rcs1Target1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
|
||
double rcs1Target2 = model.GetRealtimeRcs(TargetId2, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false); // 另一个目标以验证其缓存不受影响
|
||
|
||
// 操作 (Act)
|
||
model.ClearCachedRcs(TargetId1); // 清除TargetId1的缓存
|
||
double rcs2Target1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false); // 重新获取TargetId1的RCS
|
||
double rcs2Target2 = model.GetRealtimeRcs(TargetId2, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false); // 再次获取TargetId2的RCS
|
||
|
||
// 断言 (Assert)
|
||
Assert.AreNotEqual(rcs1Target1, rcs2Target1, "清除缓存后,TargetId1的RCS值应重新采样而不同(高概率)。");
|
||
Assert.AreEqual(rcs1Target2, rcs2Target2, "清除TargetId1的缓存不应影响TargetId2的缓存值。");
|
||
Assert.IsTrue(rcs1Target1 > 0);
|
||
Assert.IsTrue(rcs2Target1 > 0);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:ClearAllCachedRcs应清除所有目标的缓存,导致下次所有慢起伏目标调用都重新采样。
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void ClearAllCachedRcs_SlowFluctuation_ForcesNewSamplesForAllTargets()
|
||
{
|
||
// 准备 (Arrange)
|
||
var model = new SwerlingRcsModel(TestSeed);
|
||
double rcs1Target1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
|
||
double rcs1Target2 = model.GetRealtimeRcs(TargetId2, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
|
||
|
||
// 操作 (Act)
|
||
model.ClearAllCachedRcs(); // 清除所有缓存
|
||
double rcs2Target1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
|
||
double rcs2Target2 = model.GetRealtimeRcs(TargetId2, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
|
||
|
||
// 断言 (Assert)
|
||
Assert.AreNotEqual(rcs1Target1, rcs2Target1, "清除所有缓存后,TargetId1的RCS值应重新采样而不同(高概率)。");
|
||
Assert.AreNotEqual(rcs1Target2, rcs2Target2, "清除所有缓存后,TargetId2的RCS值应重新采样而不同(高概率)。");
|
||
Assert.IsTrue(rcs1Target1 > 0);
|
||
Assert.IsTrue(rcs1Target2 > 0);
|
||
Assert.IsTrue(rcs2Target1 > 0);
|
||
Assert.IsTrue(rcs2Target2 > 0);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:使用相同种子的两个SwerlingRcsModel实例应产生可复现的RCS序列。
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void GetRealtimeRcs_WithSameSeed_GeneratesReproducibleSequence()
|
||
{
|
||
// 准备 (Arrange)
|
||
var model1 = new SwerlingRcsModel(TestSeed);
|
||
var model2 = new SwerlingRcsModel(TestSeed);
|
||
|
||
// 操作 (Act) & 断言 (Assert)
|
||
// 以Swerling II (快起伏) 为例,因为它不依赖缓存和isNewScanPeriod
|
||
for (int i = 0; i < 10; i++)
|
||
{
|
||
double rcsM1 = model1.GetRealtimeRcs(TargetId1, EquipmentType.Helicopter, MotionStateType.Static, DefaultAverageRcs, false);
|
||
double rcsM2 = model2.GetRealtimeRcs(TargetId1, EquipmentType.Helicopter, MotionStateType.Static, DefaultAverageRcs, false);
|
||
Assert.AreEqual(rcsM1, rcsM2, $"在第 {i+1} 次调用时,使用相同种子的两个模型产生的RCS值应相同。");
|
||
Assert.IsTrue(rcsM1 > 0, $"Model1, 调用 {i+1}, RCS 值应大于0。");
|
||
}
|
||
|
||
// 测试Swerling I (慢起伏)
|
||
double rcsS1M1_Initial = model1.GetRealtimeRcs(TargetId2, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, true);
|
||
double rcsS1M2_Initial = model2.GetRealtimeRcs(TargetId2, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, true);
|
||
Assert.AreEqual(rcsS1M1_Initial, rcsS1M2_Initial, "Swerling I,相同种子,首次调用(isNewScanPeriod=true),RCS值应相同。");
|
||
|
||
double rcsS1M1_Cached = model1.GetRealtimeRcs(TargetId2, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
|
||
double rcsS1M2_Cached = model2.GetRealtimeRcs(TargetId2, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
|
||
Assert.AreEqual(rcsS1M1_Cached, rcsS1M2_Cached, "Swerling I,相同种子,后续调用(isNewScanPeriod=false),缓存的RCS值应相同。");
|
||
Assert.AreEqual(rcsS1M1_Initial, rcsS1M1_Cached, "Swerling I,Model1,后续调用应返回首次缓存的值。");
|
||
}
|
||
}
|
||
} |