Как правильно проверить что-то вроде расчета большого круга?

Каков наилучший способ проверить то, что не совпадает с точными значениями, например, вычисление большого круга:

/// <summary>
///  Get the great circle distance (shortest distance possible) between two points in km.
/// </summary>
/// <param name="endPoint">end point</param>
/// <returns>the great circle distance in km</returns>
public double GreatCircleDistanceInKm(IGeoPoint endPoint)
{
    var earthRadius = Constants.EARTH_RADIUS_KM;
    var diffLat = Utility.DegreesToRadians(endPoint.Latitude - this.Latitude);
    var diffLong = Utility.DegreesToRadians(endPoint.Longitude - this.Longitude);

    var a = Math.Sin(diffLat / 2) * Math.Sin(diffLat / 2) +
            Math.Cos(Utility.DegreesToRadians(this.Latitude)) * Math.Cos(Utility.DegreesToRadians(endPoint.Latitude)) *
            Math.Sin(diffLong / 2) * Math.Sin(diffLong / 2);
    var c = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a)));
    var d = earthRadius * c;

    return d;
}

В настоящее время мой тест выглядит так:

[TestMethod]
public void GeoPoint_GreatCircleDistanceInKm_IsCorrect()
{
    // arrange
    var startPoint = new GeoPoint(0, 45, 90); // id, lat, long
    var endPoint1 = new GeoPoint(0, 45, 90);
    var endPoint2 = new GeoPoint(0, 0, 0);

    // act
    var greatCircleDistanceZero = startPoint.GreatCircleDistanceInKm(endPoint1);
    var greatCircleDistanceBig = startPoint.GreatCircleDistanceInKm(endPoint2);

    // assert
    Assert.AreEqual(0, greatCircleDistanceZero);
    Assert.AreEqual(10007.543398010288, greatCircleDistanceBig);
}

Но это кажется неправильным, я сначала нахожу ответ, а затем проверяю его. Как такие методы должны быть проверены? Должен ли я пройти алгоритм / расчет и попытаться выяснить, как он работает, чтобы я мог привести к точным значениям?

Пояснение: мой вопрос, это правильный метод проведения теста для таких вещей, т.е. Должен ли мой тест быть привязан к реальной реализации (потому что, как вы видите, я использую детализированное ожидаемое значение) или он должен быть как-то более общим?

3 ответа

Решение

Ты можешь использовать Assert.AreEqual(double expected, double actual, double delta), Вы должны использовать дельту, которая достаточно мала (например, 0,00000001). Использование double.Epsilon здесь не рекомендуется.

Из MSDN:

Поскольку Epsilon определяет минимальное выражение положительного значения, диапазон которого близок к нулю, разница в разнице между двумя одинаковыми значениями должна быть больше, чем у Epsilon. Как правило, это во много раз больше, чем Эпсилон. В связи с этим мы рекомендуем не использовать Epsilon при сравнении значений Double на равенство.

На другие ваши вопросы: Да, такие методы должны быть проверены. Но не рекомендуется писать тесты после проверки того, как реализован алгоритм, потому что он может быть реализован неправильно. Вам нужно общее представление о том, что, например, должен делать метод (в вашем случае вычисление расстояния вокруг круга). Теперь вы можете указать контрольные примеры, указав ввод и ожидаемый вывод. Вы можете получить ожидаемый результат из другого источника (например, рассчитав его вручную).

Небольшое примечание: в тестах TDD обычно указывается перед написанием реального кода. Таким образом, нет алгоритма, который вы можете пройти и выяснить, как он работает.

В следующей таблице показано расстояние между двумя точками на экваторе. Поскольку широта перемещается от полюсов, расстояние NS является постоянным, но расстояние EW уменьшается. Поскольку я предполагаю, что при использовании Great Circle Distance любая точность, превышающая 2 десятичных знака в ваших результатах, является избыточной.

0 decimal places    1.0  = 111.32 km  
1 decimal places    0.1 = 11.132 km 
2 decimal places    0.01 = 1.1132 km 
3 decimal places    0.001 = 111.32 m 
4 decimal places    0.0001 = 11.132 m   
5 decimal places    0.00001 = 1.1132 m 

Может быть

Assert.IsTrue(Math.Abs(greatCircleDistanceZero - 0) < Double.Epsilon);
Assert.IsTrue(Math.Abs(greatCircleDistanceBig - 10007.543398010288) < Double.Epsilon);
Другие вопросы по тегам