如何使用NUnit中指定的容差比较双精度

本文关键字:比较 双精度 何使用 NUnit | 更新日期: 2023-09-27 18:15:02

我目前正在开发一个c# p/invoke包装器,它是我的产品的一部分。我没有c#的经验,这是我做的第一个重要的c#编码。我强烈地意识到我在语言的细节和习语方面缺乏很多知识。

我的问题是关于我使用NUnit编写的单元测试。我需要比较double[]变量的值。如果我用Assert.AreEqual(...)来做这个,那么值就会被比较为完全相等。但是,我想比较一下,要有忍耐力。对于允许delta参数的标量实值存在AreEqual()过载。然而,我还没能找到数组的等效。我错过了什么明显的东西吗?

现在我用下面的代码解决了这个问题:

class Assert : NUnit.Framework.Assert
{
    public static void AreEqual(double[] expected, double[] actual, double delta)
    {
        AreEqual(expected.Length, actual.Length);
        for (int i = 0; i < expected.Length; i++)
        {
            AreEqual(expected[i], actual[i], delta);
        }
    }
}

虽然这似乎工作,我想知道是否有一个更干净的解决方案。我特别关心的是,对派生类使用相同的名称不仅是糟糕的风格,而且可能导致意想不到的问题。

我想使用扩展方法,但我理解它们只适用于当有一个类的实例在扩展。当然,我只在Assert类上调用静态方法。

我很抱歉,如果这看起来有点模糊,但我的直觉告诉我,我这样做不是最好的方式,我想知道如何做正确的

如何使用NUnit中指定的容差比较双精度

自从在NUnit中引入流畅的断言语法以来,Within()方法已可用于此目的:

double actualValue = 1.989;
double expectedValue = 1.9890;
Assert.That(actualValue, Is.EqualTo(expectedValue).Within(0.00001));
Assert.That(actualValue, Is.EqualTo(expectedValue).Within(1).Ulps);
Assert.That(actualValue, Is.EqualTo(expectedValue).Within(0.1).Percent);

对于集合,Is.EqualTo()的默认行为是单独比较集合的成员,这些单独的比较由Within()修改。因此,可以像这样比较两个双精度数组:

var actualDoubles = new double[] {1.0 / 3.0, 0.7, 9.981};
var expectedDoubles = new double[] { 1.1 / 3.3, 0.7, 9.9810};
Assert.That(actualDoubles, Is.EqualTo(expectedDoubles).Within(0.00001));
Assert.That(actualDoubles, Is.EqualTo(expectedDoubles).Within(1).Ulps);
Assert.That(actualDoubles, Is.EqualTo(expectedDoubles).Within(0.1).Percent);

actualDoubles中的每个元素与expectedDoubles中的相应元素使用指定的容差进行比较,如果没有足够接近,则将失败。

我需要创建自定义断言,在您的情况下,框架提供了另一种选择。然而,当我想要一个完全自定义的断言时,这不起作用。我通过在nunit中添加一个新的静态类调用来解决这个问题。

public static class FooAssert
{
     public static void CountEquals(int expected, FooConsumer consumer)
     {
         int actualCount = 0;
         while (consumer.ConsumeItem() != null)
             actualCount++;
         NUnit.Framework.Assert.AreEqual(expected, actualCount);
     }
}

在一个测试中

[Test]
public void BarTest()
{
    // Arrange
    ... 
    // Act
    ...
    // Assert
    FooAssert.CountEquals(1, fooConsumer);
}

我知道我迟到了一点,但它可能对某人还是有用的

"更好"永远是品位问题。在这种情况下,我会说是的。您应该创建自己的断言,而不子类化非单元断言。Nunit已经有多个带有不同特定断言的Assert类。像CollectionAssert。

我想我要做的就是简单地在你的测试工具中定义一个函数

public static bool AreEqual( double[], double[], double delta )

进行比较并适当地返回真或假。在你的测试中,你只需写:

Assert.IsTrue( AreEqual( expected, result, delta ) ) ;