C#单元测试中双字节数组DataRow仅生效最后一行的问题排查
问题描述
编写包含多个[DataRow]的[DataTestMethod]时,每个DataRow传入两个byte数组,但测试仅执行最后一行DataRow的用例。此前仅含整数、或单个byte数组搭配bool值的DataRow测试均可正常运行,仅双byte数组的多DataRow测试异常。
正常工作的测试代码
[DataTestMethod] [DataRow(1, 1, 2)] [DataRow(2, 2, 4)] [DataRow(3, 3, 6)] public void AddTests(int x, int y, int expected) { Assert.AreEqual(expected, x + y); } [DataRow(new byte[] { 0x00 }, false, false, false)] [DataRow(new byte[] { 0x00 }, true, true, false)] [DataRow(new byte[] { 0x00 }, false, true, false)] [DataRow(new byte[] { 0x00 }, true, false, false)] [DataTestMethod()] public void ByteArrayIntegerTest(byte[] key,bool ctorsign, bool tasign,bool expectfail) { var bi = new ByteArrayInteger(key, ctorsign); var result = bi.ToByteArray(tasign); if (expectfail) { CollectionAssert.AreNotEqual(key, result); } else { CollectionAssert.AreEqual(key, result); } }
无法正常工作的测试代码
[DataTestMethod] [DataRow(new byte[] { 0xCA, 0xFE }, new byte[] { 0xCA, 0xFE })] [DataRow(new byte[] { 0x00, 0xCA, 0xFE }, new byte[] { 0xCA, 0xFE })] [DataRow(new byte[] { 0x00, 0x00, 0xCA, 0xFE }, new byte[] { 0xCA, 0xFE })] public void MinimizeSerialnumberTest(byte[] serialnumber, byte[] expected) { CollectionAssert.AreEqual(expected, Util.MinimizeSerialnumber(serialnumber)); }
测试无报错,但仅执行最后一行DataRow的测试用例。疑问:Microsoft.VisualStudio.TestTools.UnitTesting不支持多byte数组的DataRow吗?是否因为DataRowAttribute的构造函数参数为Object, Object[]导致该问题?如何解决?
问题原因与解决方案
原因
问题确实和DataRowAttribute的构造函数参数机制有关。DataRowAttribute的构造参数要求是编译时常量,而byte数组属于引用类型,在多个DataRow中初始化的数组会被框架错误地共享引用——后续DataRow的数组会覆盖前面的实例,最终所有测试用例都指向最后一个DataRow的数组对象。
解决方案
推荐使用DynamicDataAttribute替代DataRowAttribute,它支持动态生成测试数据,能正确处理引用类型的参数传递,避免数组引用被复用的问题。
示例代码改造如下:
[DataTestMethod] [DynamicData(nameof(GetMinimizeSerialnumberTestData), DynamicDataSourceType.Method)] public void MinimizeSerialnumberTest(byte[] serialnumber, byte[] expected) { CollectionAssert.AreEqual(expected, Util.MinimizeSerialnumber(serialnumber)); } // 静态方法提供测试数据 public static IEnumerable<object[]> GetMinimizeSerialnumberTestData() { yield return new object[] { new byte[] { 0xCA, 0xFE }, new byte[] { 0xCA, 0xFE } }; yield return new object[] { new byte[] { 0x00, 0xCA, 0xFE }, new byte[] { 0xCA, 0xFE } }; yield return new object[] { new byte[] { 0x00, 0x00, 0xCA, 0xFE }, new byte[] { 0xCA, 0xFE } }; }
其他可选方案
如果坚持使用DataRowAttribute,可以通过将byte数组强制转换为object类型,避免引用复用问题(但这种方式可靠性较低,不推荐):
[DataTestMethod] [DataRow((object)new byte[] { 0xCA, 0xFE }, (object)new byte[] { 0xCA, 0xFE })] [DataRow((object)new byte[] { 0x00, 0xCA, 0xFE }, (object)new byte[] { 0xCA, 0xFE })] [DataRow((object)new byte[] { 0x00, 0x00, 0xCA, 0xFE }, (object)new byte[] { 0xCA, 0xFE })]
内容的提问来源于stack exchange,提问作者Sven
相关产品推荐
相关产品推荐

