Làm thế nào tôi có thể so sánh đúng các giá trị kép cho sự bằng nhau trong một bài kiểm tra đơn vị?


20

Gần đây tôi đã thiết kế một mô-đun chuỗi thời gian trong đó chuỗi thời gian của tôi về cơ bản là a SortedDictionnary<DateTime, double>.

Bây giờ tôi muốn tạo các bài kiểm tra đơn vị để đảm bảo rằng mô-đun này luôn hoạt động và tạo ra kết quả mong đợi.

Một hoạt động phổ biến là tính toán hiệu suất giữa các điểm trong chuỗi thời gian.

Vì vậy, những gì tôi làm là tạo một chuỗi thời gian với, giả sử, {1.0, 2.0, 4.0} (tại một số ngày) và tôi hy vọng kết quả sẽ là {100%, 100%}.

Vấn đề là, nếu tôi tự tạo một chuỗi thời gian với các giá trị {1.0, 1.0} và tôi kiểm tra sự bằng nhau (bằng cách so sánh từng điểm), thử nghiệm sẽ không vượt qua, vì sẽ luôn có sự không chính xác khi làm việc với các biểu diễn nhị phân của thực số.

Do đó, tôi quyết định tạo chức năng sau:

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

Có một cách phổ biến khác để đối phó với một trường hợp như vậy?

Câu trả lời:


10

Tôi có thể nghĩ ra hai cách khác để giải quyết vấn đề này:

Bạn có thể sử dụng Is.InRange:

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

Bạn có thể sử dụng Math.Round:

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

Tôi nghĩ rằng cả hai cách đều biểu cảm hơn một chức năng chuyên dụng, bởi vì người đọc có thể thấy chính xác những gì đang xảy ra với số của bạn trước khi nó được so sánh với giá trị mong đợi.


2
Chỉ cần lưu ý rằng câu trả lời này là cụ thể của NUnit và giới thiệu mô hình khẳng định "Dựa trên ràng buộc". Mô hình khẳng định cổ điển sẽ trông giống như: Assert.AreEqual (dự kiến, thực tế, khoan dung);
RichardM

1
@RichardM: Đăng nó như một câu trả lời và tôi sẽ chọn nó chấp nhận nó.
SRKX

Câu trả lời của @dasblinkenlight là chính xác, chỉ cần thêm một số chi tiết (vì nó có thể không rõ ràng - mô hình khẳng định cổ điển cũng là NUnit). Các khung kiểm tra khác (không phải MSTest) có thể có mô hình khẳng định riêng để xử lý các giá trị dấu phẩy động.
RichardM

1
Assert.That(result, Is.InRange(expected-tolerance, expected+tolerance));sẽ thất bại nếu tolerance/abs(expected) < 1E-16.
quant_dev

@quant_dev Bạn hoàn toàn đúng. Vì OP nói về việc tính toán lợi nhuận theo tỷ lệ phần trăm, tôi cho rằng đó abs(expected)sẽ là một đến hai chữ số. Tôi cũng giả định dung sai trong vùng lân cận của 1E-9. Theo các giả định này, phương pháp đơn giản được thừa nhận này có thể phục vụ bạn một cách hợp lý (tôi sử dụng Is.InRangetrong các thử nghiệm của mình).
dasblinkenlight


3

Nó phụ thuộc vào những gì bạn làm với những con số. Nếu bạn đang thử nghiệm một phương thức được cho là ví dụ: chọn một giá trị phù hợp từ một bộ đầu vào dựa trên một số tiêu chí, thì bạn nên kiểm tra sự bình đẳng nghiêm ngặt. Nếu bạn đang thực hiện các phép tính dấu phẩy động, thông thường bạn sẽ cần kiểm tra với dung sai khác không. Độ dung sai lớn đến mức nào tùy thuộc vào các phép tính, nhưng với độ chính xác gấp đôi, điểm khởi đầu tốt là chọn dung sai tương đối 1E-14 cho các phép tính đơn giản và 1E-8 (dung sai) cho các phép tính phức tạp hơn. YMMV tất nhiên, và bạn cần thêm một số dung sai tuyệt đối nhỏ nếu kết quả mong đợi là 0.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.