C#单元测试:如何创建COM互操作值的测试输入?
解决方案
方法一:构造模拟对象替代IADSLargeInteger
被测方法通过反射读取HighPart和LowPart属性,不需要依赖真实的COM对象,只要构造一个包含这两个属性的普通对象即可。
方式1:自定义模拟类
public class MockLargeInteger { public int HighPart { get; set; } public int LowPart { get; set; } }
单元测试中使用:
public void ConvertLargeIntegerToLong_ComObjectLargeInt_Long() { var expectedValue = 94294967295L; // 计算对应值:94294967295 = 0x15FFFFFFFF → HighPart=21,LowPart=-1(int类型的0xFFFFFFFF) var testValue = new MockLargeInteger { HighPart = 21, LowPart = -1 }; var result = ConvertLargeIntegerToLong(testValue); Assert.AreEqual(expectedValue, result); }
方式2:用匿名类型简化
public void ConvertLargeIntegerToLong_ComObjectLargeInt_Long() { var expectedValue = 94294967295L; var testValue = new { HighPart = 21, LowPart = -1 }; var result = ConvertLargeIntegerToLong(testValue); Assert.AreEqual(expectedValue, result); }
方法二:重构被测方法,拆分逻辑简化测试
原方法将反射获取属性与数值转换逻辑耦合,可拆分出纯转换逻辑的方法,单独测试核心计算逻辑:
public static long ConvertLargeIntegerToLong(object largeInteger) { var type = largeInteger.GetType(); var highPart = (int)type.InvokeMember("HighPart", BindingFlags.GetProperty, null, largeInteger, null)!; var lowPartInt = (int)type.InvokeMember("LowPart", BindingFlags.GetProperty | BindingFlags.Public, null, largeInteger, null)!; // 把转换逻辑提取为独立方法 return ConvertHighLowToLong(highPart, lowPartInt); } public static long ConvertHighLowToLong(int highPart, int lowPartInt) { uint lowPartUint; unchecked { lowPartUint = (uint)lowPartInt; } return (long)highPart << 32 | (long)lowPartUint; }
针对提取出的方法编写全面测试:
[Test] public void ConvertHighLowToLong_VariousCases_ReturnsCorrectValue() { // 测试目标值案例 Assert.AreEqual(94294967295L, ConvertHighLowToLong(21, -1)); // 正数LowPart案例 Assert.AreEqual(12345L, ConvertHighLowToLong(0, 12345)); // 负数HighPart案例 Assert.AreEqual(-4294967296L, ConvertHighLowToLong(-1, 0)); // 零值案例 Assert.AreEqual(0L, ConvertHighLowToLong(0, 0)); }
额外说明
如果一定要模拟真实的COM对象,可以通过Type.GetTypeFromCLSID获取IADSLargeInteger类型并创建实例,但这种方式依赖Active Directory环境,不符合单元测试“无外部依赖”的原则,不推荐使用。
内容的提问来源于stack exchange,提问作者Zarepheth
相关产品推荐
相关产品推荐

