ThreatSourceLibaray/ThreatSource.Tests/SwerlingRcsModelTests.cs

388 lines
20 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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=falseRCS值应从缓存读取且保持不变。");
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 IModel1后续调用应返回首次缓存的值。");
}
}
}