Bagaimana saya bisa membandingkan nilai ganda untuk kesetaraan dalam pengujian unit?

20

Saya baru-baru ini merancang modul deret waktu di mana deret waktu saya pada dasarnya adalah a SortedDictionnary<DateTime, double>.

Sekarang saya ingin membuat unit test untuk memastikan bahwa modul ini selalu berfungsi dan menghasilkan hasil yang diharapkan.

Operasi yang umum adalah menghitung kinerja antara titik-titik dalam deret waktu.

Jadi yang saya lakukan adalah membuat rangkaian waktu dengan, katakanlah, {1.0, 2.0, 4.0} (di beberapa tanggal), dan saya berharap hasilnya adalah {100%, 100%}.

Masalahnya adalah, jika saya secara manual membuat seri waktu dengan nilai-nilai {1.0, 1.0} dan saya memeriksa kesetaraan (dengan membandingkan setiap titik), tes tidak akan lulus, karena akan selalu ada ketidakakuratan ketika bekerja dengan representasi biner nyata angka.

Karenanya, saya memutuskan untuk membuat fungsi berikut:

private static bool isCloseEnough(double expected, double actual, double tolerance=0.002)
{
    return squaredDifference(expected, actual) < Math.Pow(tolerance,2);
}

Apakah ada cara lain yang umum untuk menangani kasus seperti itu?

SRKX
sumber

Jawaban:

10

Saya dapat memikirkan dua cara lain untuk mengatasi masalah ini:

Anda bisa menggunakan Is.InRange:

Assert.That(result, Is.InRange(expected-tolerance, expected+tolerance));

Anda bisa menggunakan Math.Round:

Assert.That(Math.Round(result, sigDigits), Is.EqualTo(expected));

Saya pikir kedua cara itu lebih ekspresif daripada fungsi khusus, karena pembaca dapat melihat dengan tepat apa yang terjadi dengan nomor Anda sebelum dibandingkan dengan nilai yang diharapkan.

dasblinkenlight
sumber
2
Hanya perlu dicatat bahwa jawaban ini adalah spesifik NUnit dan menampilkan model pernyataan "Berbasis Constraing". Model asersi klasik akan terlihat seperti: Assert.AreEqual (diharapkan, aktual, toleransi);
RichardM
1
@RichardM: Posting itu sebagai jawaban dan saya akan memilih menerimanya.
SRKX
Jawaban oleh @dasblinkenlight benar, hanya menambahkan beberapa detail (karena mungkin tidak jelas - model pernyataan klasik juga NUnit). Kerangka kerja pengujian lainnya (bukan MSTest) kemungkinan memiliki model yang tegas untuk menangani nilai floating point.
RichardM
1
Assert.That(result, Is.InRange(expected-tolerance, expected+tolerance));akan gagal jika tolerance/abs(expected) < 1E-16.
quant_dev
@quant_dev Anda benar sekali. Karena OP berbicara tentang menghitung pengembalian sebagai persentase, saya berasumsi bahwa itu abs(expected)akan menjadi digit tunggal ke ganda. Saya juga mengasumsikan toleransi di sekitar 1E-9. Berdasarkan asumsi ini, pendekatan yang diakui sederhana ini dapat membantu Anda dengan cukup baik (saya gunakan Is.InRangedalam tes saya).
dasblinkenlight
6

Seperti yang disarankan RichardM, jika Anda tidak menggunakan NUnit, cara terbaik tampaknya menggunakan Assert.AreEqual (double, double, double) , di mana yang terakhir adalah ketepatan.

SRKX
sumber
3

Itu tergantung apa yang Anda lakukan dengan angka. Jika Anda menguji suatu metode yang seharusnya misalnya memilih nilai yang sesuai dari set input berdasarkan beberapa kriteria, maka Anda harus menguji kesetaraan yang ketat. Jika Anda melakukan perhitungan floating-point, biasanya Anda perlu menguji dengan toleransi nol. Seberapa besar toleransi tergantung pada perhitungan, tetapi dengan presisi ganda titik awal yang baik adalah memilih 1E-14 toleransi relatif untuk perhitungan sederhana dan 1E-8 (toleransi) untuk yang lebih rumit. YMMV tentu saja, dan Anda perlu menambahkan sedikit toleransi absolut jika hasil yang diharapkan adalah 0.

quant_dev
sumber