我使用一个项目,其中一些类执行数值插值,也就是说,在已知位置给定一组点,我可以询问网格节点之间的点的位置,可以这么说。
由于这些方法没有按定义返回确切的值,我想知道我应该如何对它们进行单元测试。
例如,下面的代码测试插值返回一个零数组,如果我给它一个类似的零数组,它可以工作,但我怀疑它是有效的,因为我实际上并没有重新采样,只是再次询问相同的立场。
[TestMethod]
public void Interpolate_ZeroIn_ZeroOut()
{
var Xvalues = new double[] {1,2,3,4,5,6,7,8,9,10};
var Yvalues = new double[] {0,0,0,0,0,0,0,0,0,0};
List<Point> points =
Enumerable.Zip(Xvalues, Yvalues, (x,y) => new Point(x,y)).ToList();
int interpolation_order = 5;
FourierIterpolator target = new FourierInterpolator(points, interpolation_order);
var output = Xvalues.Select(p => target.Interpolate(p)).ToList();
CollectionAssert.AreEqual(output, Yvalues);
}
问题是:通过实际重新采样,新点将在&#34;之间&#34;输入点,所以我不能使用CollectionAssert.AreEqual
。此外,对于一些使用平滑的插值方法,数组将不相等,只是近似值。
所以,我的问题是:
在测试涉及aproximation / interpolation的数值方法时,建议使用哪些断言?
答案 0 :(得分:2)
您的插值技术确定性? (确定性表示:如果使用相同的参数调用两次方法,那么在两种情况下它都会返回完全相同的结果吗?)
如果是,
这将确保测试用例检测到您的方法的任何更改。一个缺点是,如果您改进插值技术,您的情况将会失败,从而产生不同的结果。这不一定是坏事,因为它会提醒您,您的方法现在会返回不同的结果。
如果插值技术不是确定性的,即,如果它使用某种随机源,您可能会断言这些值在一些合理的误差范围内。
答案 1 :(得分:2)
目前很难看出测试的输入数据是什么。我建议你让测试数据明确且易于查看。此外,我认为您不需要10或100分来验证您的方法是否有效。可能2-3分就足够了:
var points = new []{ new Point(0,0), new Point(1,0), new Point(2,0) });
接下来,您应提供预期值:
double[] expected = { 0.33, 0.66, 1.66 };
最后 - 检查实际值是否等于或接近预期值:
[TestMethod]
public void Interpolar_ZeroIn_ZeroOut()
{
var points = new []{ new Point(0,0), new Point(1,0), new Point(2,0) });
// calculate expected values manually
double[] expected = { 0.33, 0.66, 1.66 };
int ordem = 5;
var interpolator = new InterpoladorFourier(points, ordem);
for(int i = 0; i < points.Length; i++)
Assert.AreEqual(expected[i], interpolator.Interpolar(points[i].X));
}
如果预期数据不准确,那么您可以为断言提供delta:
Assert.AreEqual(expected[i], interpolator.Interpolar(points[i].X), 0.01);
甚至更好 - 您可以创建以非常易读的方式创建点的方法:
var points = CreatePoints("0,0", "1,0", "2,0");
使用这个辅助方法:
private Point[] CreatePoints(params string[] points)
{
List<Point> result = new List<Point>();
foreach(var s in points)
{
var parts = s.Split(',');
var x = Double.Parse(parts[0]);
var y = Double.Parse(parts[1]);
var point = new Point(x,y);
result.Add(point);
}
return result.ToArray();
}
答案 2 :(得分:0)
我通过谷歌来到这里是因为我自己也在寻找一些答案,但我目前的方法可能比这里提供的方法更好,所以我会分享以供将来参考。
大多数(如果不是全部)插值方法都有相当数量的函数,它们可以完美地或至少达到机器精度。例如三次样条,它的多项式达到 3 次。我只是测试合理数量的具有不同系数、不同间隔、不同点数的多项式......如果它接近机器精度,则计算 RMS 误差并“断言” (比如 rms_err < 10*eps)。准确选择适合此处的多项式/函数/参数需要了解有关特定插值方法的一些知识,可能还有浮点误差,但这是可行的。
另一种方法是与具有相同或相似实现的可用库进行比较,或者直接导出仅使用库的值。例如,我使用可用的 1D 实现测试了我的 2D 插值实现,这些实现使用相同的方法,当然是沿着一个维度。