[英]How should I unit-test a class which performs numeric interpolation of arrays?
我在一個項目中工作,其中一些類執行數值插值,也就是說,給定一組已知位置的點,我可以要求網格節點之間的點的位置,可以這么說。
由於這些方法根據定義不返回精確值,我想知道我應該如何對它們進行單元測試。
例如,下面的代碼測試如果我給它一個類似的零數組,則插值器返回一個零數組,並且它有效,但我懷疑它有效,因為我實際上並沒有在這里重新采樣,只是再次詢問相同的位置。
[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
。 此外,使用一些帶平滑的插值方法,數組將不相等,只有近似值。
所以,我的問題是:
在測試涉及近似/插值的數值方法時推薦使用哪些斷言?
您的插值技術是確定性的嗎? (確定性意味着:如果您的方法使用相同的參數被調用兩次,它會在兩種情況下返回完全相同的結果嗎?)
如果是,
這將確保測試用例檢測到您的方法的任何重大更改。 一個缺點是,如果您改進插值技術,您的案例將失敗,從而產生不同的結果。 這不一定是壞事,因為它會提醒您您的方法現在返回不同的結果。
如果您的插值技術不是確定性的,即,如果它使用一些隨機源,您可能能夠斷言這些值在一些合理的誤差范圍內。
目前很難看到測試的輸入數據是什么。 我建議您使測試數據明確且易於查看。 此外,我認為您不需要 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));
}
如果預期數據不准確,那么您可以為斷言提供增量:
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 誤差並“斷言” (比如 rms_err < 10*eps)。 准確選擇哪些多項式/函數/參數適合此處需要一些關於特定插值方法的知識,可能還有浮點錯誤,但這是可行的。
另一種方法是與具有相同或相似實現的可用庫進行比較,或者直接導出僅使用庫的值。 例如,我使用可用的 1D 實現測試了我的 2D 插值實現,這些實現使用相同的方法,當然沿着一個維度。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.