为啥 Assert.AreEqual(1.0, double.NaN, 1.0) 通过?
Posted
技术标签:
【中文标题】为啥 Assert.AreEqual(1.0, double.NaN, 1.0) 通过?【英文标题】:Why does Assert.AreEqual(1.0, double.NaN, 1.0) pass?为什么 Assert.AreEqual(1.0, double.NaN, 1.0) 通过? 【发布时间】:2010-12-19 07:07:08 【问题描述】:简短的问题,为什么Assert.AreEqual(1.0, double.NaN, 1.0)
通过?而Assert.AreEqual(1.0, double.NaN)
失败。
这是 MSTest (Microsoft.VisualStudio.QualityTools.UnitTestFramework) 中的错误还是我在这里遗漏了什么?
最好的问候,埃吉尔。
更新:应该补充一下,我的问题背后的原因是,由于某些线性代数矩阵运算的结果是 NaN 或 (+/-)Infinity,我有一堆单元测试不幸通过了。单元测试很好,但是由于当实际或/和预期为 NaN 或 Infinity 时,带有 delta 的双精度的 Assert.AreEqual 将通过,所以我只能相信我正在测试的代码是正确的。
【问题讨论】:
微软错误条目:connect.microsoft.com/VisualStudio/feedback/details/762286/… 白痴将其关闭为“设计”。 有趣,因为 MS 放弃并说它现在已修复:connect.microsoft.com/VisualStudio/feedback/details/780654/… 这是一个错误。当 x 为 NaN 时,您完全可以预期测试“|x-1| ≤ 0.1”会失败,就像 x=3 时一样。暗示这是用户错误是荒谬的。 答案已过时。如果错误已被修复,何时以及在哪个程序集的哪个版本中? 【参考方案1】:小心。 NaN 很奇怪,有点像许多 DBMS 中的 null,您不应该将值与它进行比较(直接或使用 Assert.AreEqual)。来自Double.NaN 的文档:
使用 IsNaN 判断一个值是否 不是一个数字。这是不可能的 判断一个值是否不是 通过将其与另一个进行比较来获得数字 值等于 NaN。
double zero = 0;
Console.WriteLine((0 / zero) == Double.NaN); // prints false
Console.WriteLine(Double.IsNaN(0 / zero)); // prints true
您必须查看 Assert(double, double, double) 的内部以了解发生了什么,但通常,您依赖于相对于 NaN 的未定义行为。
【讨论】:
我的问题背后的故事是一堆单元测试,不幸的是,由于某些线性代数矩阵运算的结果是 NaN/(+/-)Infinity,这些单元测试通过了。单元测试很好,但是由于当实际或/和预期为 NaN 或 Infinity 时,带有 delta 的双精度数上的 Assert.AreEqual 将通过,所以我不得不相信我的代码确实有效...... 我明白了。从表面上看,这种行为是不正确的,您有理由在 Microsoft Connect 上提出问题。如果你愿意,可以连接一个符号服务器,看看 Assert.AreEqual(double, double) 与 Assert.AreEqual(double, double, double) 有何不同。【参考方案2】:答案已过时。如果错误已被修复,何时以及在哪个程序集的哪个版本中?
没错,它已在 VS2013 中使用 Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll 程序集版本 10.0.0.0 修复。存在于旧版 GAC 中,c:\windows\assembly,它也有 10.1.0.0 版本。
这里有一个 DLL Hell 故事,10.1.0.0 版本是 VS2010 中使用的版本。它有错误,没有正确检查 Double.NaN。微软犯了一个错误,他们修复了 10.1.0.0 但没有更改版本号。所以在安装 VS2013 之后安装 VS2010 的任何人都会受到伤害,它会用有缺陷的版本覆盖 DLL。
解开 DLL Hell 从未如此简单,但从connect article 以及它在我的机器上的运行方式可以看出,他们从客户的投诉中识别出故障模式。并提供了一个修复,在更新中交付。不清楚哪个,在 2014 年 7 月之后。您现在将使用 v10.0.0.0,MSTest.exe 测试运行程序和 QTAgents 有一个带有 <bindingRedirect>
的 .config 文件,该文件从 10.1.0.0 重定向到 10.0.0.0(不是一个错字)。请务必获取最新的更新,目前 4. 如果您不确定自己安装了哪些更新,请查看帮助 + 关于。
作为记录,固定代码获得了对 Double.NaN 的特定检查,如下所示:
public static void AreEqual(double expected, double actual, double delta, string message, params object[] parameters)
if ((double.IsNaN(expected) || double.IsNaN(actual)) || double.IsNaN(delta))
string str = (string) FrameworkMessages.AreEqualDeltaFailMsg((message == null) ? string.Empty : ReplaceNulls(message), expected.ToString(CultureInfo.CurrentCulture.NumberFormat), actual.ToString(CultureInfo.CurrentCulture.NumberFormat), delta.ToString(CultureInfo.CurrentCulture.NumberFormat));
HandleFail("Assert.AreEqual", str, parameters);
if (Math.Abs((double) (expected - actual)) > delta)
string str2 = (string) FrameworkMessages.AreEqualDeltaFailMsg((message == null) ? string.Empty : ReplaceNulls(message), expected.ToString(CultureInfo.CurrentCulture.NumberFormat), actual.ToString(CultureInfo.CurrentCulture.NumberFormat), delta.ToString(CultureInfo.CurrentCulture.NumberFormat));
HandleFail("Assert.AreEqual", str2, parameters);
【讨论】:
谢谢汉斯,一如既往的彻底。 “dll 地狱”解释了在我同事的机器之间重现此错误时的不一致。 似乎即使在“修复”之后,Assert.AreEqual(double.NaN, double.NaN, 0.001);
也会失败。我想在下一个补丁发布之前,我必须编写自己的双重断言。【参考方案3】:
MSTest 对Assert.AreEqual<double>(expected, actual, delta)
方法使用以下公式:
if (Math.Abs(expected - actual) > delta)
Assert.HandleFail("Assert.AreEqual", ...)
操作减少到double.NaN > delta
,在这种情况下返回true。或未定义。
【讨论】:
以上是关于为啥 Assert.AreEqual(1.0, double.NaN, 1.0) 通过?的主要内容,如果未能解决你的问题,请参考以下文章
C# 我怎么能期待 Assert.AreEqual 中的异常?
NUnit Assert.AreEqual DateTime 容差