我应该如何对一个执行数组数值插值的类进行单元测试?
本文关键字:插值 单元测试 数组 执行数 执行 一个 我应该 | 更新日期: 2023-09-27 18:18:54
我有一个项目,其中一些类执行数值插值,也就是说,给定一组已知位置的点,我可以要求网格节点之间的点的位置,可以这么说。
由于这些方法根据定义不返回精确值,我不知道该如何对它们进行单元测试。
例如,下面的代码测试如果我给插值器一个类似的零数组,它返回一个零数组,并且它工作,但我怀疑它工作,因为我实际上并没有在这里重新采样,只是再次询问相同的位置。
[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);
}
问题是:在实际重采样时,新的点将在输入点之间,所以我不能使用CollectionAssert.AreEqual
。此外,使用一些平滑的插值方法,数组不会相等,只能近似。
那么,我的问题是:
当测试涉及近似/插值的数值方法时,建议使用什么断言?
你的插值技术是确定性的吗?(Deterministic意味着:如果你的方法用相同的参数调用两次,它会在两次情况下返回完全相同的结果吗?)
如果是的,- 通过你的函数运行几个值,
- 使用外部方法来验证结果是否正确(笔和纸,或一些数学工具),
- 添加这些值作为测试用例。
如果你的插值技术不是确定性的,也就是说,如果它使用了一些随机性来源,你可能能够断言这些值在一些合理的误差范围内。
目前很难看到测试的输入数据是什么。我建议您使测试数据显式且易于查看。我也不认为你需要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();
}
我通过谷歌来到这里,因为我自己正在寻找一些答案,但我目前的方法可能比这里提供的更好,所以我将分享给将来参考。
大多数(如果不是全部)插值方法都有相当数量的函数,它们可以完美地插值或至少达到机器精度。比如一个三次样条曲线它的多项式在3次以上。我只是测试了合理数量的多项式,这些多项式有不同的系数,不同的间隔,不同的点数……计算均方根误差并"断言";如果它接近机器精度(输入rms_err <10 * eps)。选择合适的多项式/函数/参数需要对具体的插值方法和浮点误差有一定的了解,但这是可行的。
另一种方法是与具有相同或类似实现的可用库进行比较,要么直接导出值,要么直接使用库。例如,我测试了我的2D插值实现与使用相同方法的可用1D实现,当然是一次沿一个维度。