مقارنة المشكلات في dunit checkequals مع قيم حقل العملة
سؤال
أقوم بمقارنة بعض قيم العملة في Dunit ، لكنها لا تعمل على الإطلاق على الجهاز الخاص بي (العمل على الآخرين ، ولكن ليس على الألغام).
مثال:
CheckEquals(16.65, SomeCurrencyFieldValue);
يرفع:
expected: <16,65> but was: <16,65>
إذا فعل ما يلي المقارنة ثم يعمل:
var
Temp: Currency;
begin
Temp := 16.65;
CheckEquals(Temp, SomeCurrencyFieldValue);
والسؤال هو: لماذا لا تعمل المقارنة عندما أقوم بتمرير القيمة مباشرة إلى طريقة checkequals؟
المحلول
القضية لها علاقة بكيفية Currency
يتم تحويل القيم إلى Extended
القيم في وقت التشغيل مقابل كيفية تحويل الحرفيين الفاصلة إلى Extended
القيم في وقت الترجمة. إذا لم يكن التحويل هو نفسه في كلتا الحالتين ، فإن القيم تنتقل إلى CheckEquals
قد لا تقارن متساوين.
سيكون من المفيد التحقق Double
القيمة في طريقها إلى Extended
استعدادًا لدعوة الوظيفة. من شأن التحويل الإضافي أن يؤثر على القيمة الدقيقة للنتيجة.
شيء آخر يجب مراعاته هو أن 16.65 غير ممثل تمامًا مثل Extended
القيمة ، لكنها هو ممثل بالضبط مثل أ Currency
القيمة. رغم Currency
تم تصنيفه كنوع نقطة عائمة ، فهو في الحقيقة عدد صحيح 64 بت نقطة ثابتة. من المحتمل أن يكون هذا أسبابًا لطلب إضافية CheckEquals
التحميل الزائد في Dunit يأخذ ذلك في الاعتبار.
نصائح أخرى
أرى أن هناك فقط checkequals () للقيم الممتدة في مصادر Delphi 2007 Dunit. لكن يمكنك استخدام هذا:
procedure CheckEquals(expected, actual: extended; delta: extended;
msg: string = ''); overload; virtual;
وإعطاء دلتا مناسبة لقيم العملة.
واجهت نفس المشكلة. يبدو أن بعض DLLs تعدل كلمة تحكم FPU (معالج). هذا ما يفسر سبب عدم حدوث الخطأ دائمًا. يمكن أن يظهر فجأة عند إضافة بعض الاختبارات الجديدة ، التي تستخدم وحدات أخرى من جناح الاختبار السابق. أو إذا قام تحديث البرنامج بتثبيت DLLs السيئة. لقد كتبت عن مدونتي:
لقد وجدت أيضًا أن Delphi تحتوي على وظيفة Safeloadlibrary ، والتي تعيد كلمة التحكم.
وهذا ما يفسر أيضًا سبب ذكر السؤال الأصلي أن المشكلة تعتمد على الجهاز.
هنا حل مقترح:
procedure CheckEquals(expected, actual: double; Precision:integer; msg:string ='');overload;virtual;
...
procedure TAbstractTest.CheckEquals(expected, actual: double;
Precision: integer; msg: string);
var
I: Integer;
begin
FCheckCalled := true;
for I := 0 to Precision do begin
Expected := Expected * 10;
Actual := Actual * 10;
end;
if Round(Expected) <> Round(Actual) then
FailNotEquals( IntToStr(Round(Expected)), IntToStr(Round(Actual)), msg, CallerAddr);
end;
أعلم أن تطبيقه السيئ ، ولكن مجرد فكرة ، أحب أفضل "دلتا" ، وأسهل بكثير في الاستخدام.
في الإصدار الحالي من Dunit يمكنك استخدامه
procedure CheckEquals(expected, actual: extended; delta: extended; msg: string = ''); overload; virtual;
CheckEquals(0.011,0.01,0.009,'will pass');