2011-11-17 24 views
12

我目前正在开发一个C#P/invoke包装到属于我产品一部分的DLL。我没有使用C#的经验,这是我所做的第一个重要的C#编码。我非常清楚,我对语言的细节和习惯用法缺乏了解。如何通过为AreEqual添加新的静态过载来扩展NUnit Assert类?

我的问题涉及到我正在使用NUnit编写的单元测试。我需要比较double[]变量的值。如果我使用Assert.AreEqual(...)来做到这一点,那么将比较这些值的完全相等。不过,我想比较一下宽容。标量实数值有AreEqual()过载,允许参数为delta。但是,我一直无法找到数组的等价物。我错过了明显的东西吗?

在我已经用下面的代码解决了这个问题的时刻:

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课上调用静态方法。

对不起,如果这看起来有点模糊,但我的直觉告诉我,我没有这样做最好的方式,我想知道如何做到这一点。

+1

你尝试[扩展方法( http://msdn.microsoft.com/en-us/library/bb383977.aspx)? –

+5

@Ofer泽里格柯而我给你的+1我记得扩展方法,而定义的静态,只能在实例工作。 – dowhilefor

+0

那么作为现在看来,是无法做到的(除非你实现包装类,大量的艰苦和丑陋的工作)。参见[此](http://stackoverflow.com/questions/249222/can-i-add-extension-methods-to-an-existing-static-class/435617#435617)和[此](HTTP:// madprops.org/blog/static-extension-methods/)。 –

回答

7

由于引进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使用规定的公差比较相应的元素,如果有任何不足够接近将失败。

+0

非常感谢。看起来这是我希望解决问题的方式。我很感谢你在这里的时间。非常感谢。作为个人品味的事情,我发现这些流畅的界面有点不透明。一旦你把它写下来,这是有道理的,但你必须破解代码才能第一次写! –

+1

我认为这种流畅的接口技巧是'点驱动开发'。如果您使用的是像Visual Studio这样的IDE,您只需要知道链中的第一个“链接”,例如'是',那么你可以击中'.',智能感知系统会向你显示你'下一步'的所有选项。我通过这种方式了解了像Within()这样的许多功能,而不是通过阅读NUnit文档。 – Peter

2

我想我会做的只是在你的测试工具

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

,做比较,并适当地返回真或假的某处定义一个函数。在您的测试,你只要写:

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

谢谢你。这当然是一个好主意。对我来说,缺点是,我发现,当我试图实现这一点,我不得不重新实现,当你调用AreEqual与真正的标量输入,附带免费的'delta'比较。所以@dowhilefor的回答似乎更适合我的需求。谢谢关心! –

2

“更好”始终是一个品味的问题。在这种情况下,我会说是的。你应该建立你自己的断言,而不需要继承nunit断言。 Nunit已经拥有多个具有不同特定断言的Assert类。像CollectionAssert。否则你的方法很好。

+0

感谢您的支持。我没有发现其他'XXXAssert'类。于是我添加了一个'ArrayAssert'类,并将代码移到了那里。现在感觉很自然,我的不愉快的感觉已经消退。 –

2

我有需要创建自定义断言,在你的情况下有框架提供了一个替代。但是,当我想要一个完全自定义的断言时,这不起作用。我通过向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); 
    } 
} 
在测试

​​

我知道我是有点晚了党

然后,它可能仍然是有用的人

相关问题