Сравнение проблем в DUnit CheckEquals со значениями поля Currency
Вопрос
Я сравниваю некоторые значения валюты в 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, которая учитывает это.
Другие советы
Я вижу, что в источниках Delphi 2007 DUnit есть только CheckEquals() для расширенных значений.Но вы могли бы использовать это:
procedure CheckEquals(expected, actual: extended; delta: extended;
msg: string = ''); overload; virtual;
и дайте правильную дельту для значений валют.
Я столкнулся с той же самой проблемой.Похоже, что некоторые библиотеки DLL изменяют управляющее слово FPU (процессора).Это объясняет, почему ошибка возникает не всегда.Это может появиться внезапно, когда добавляются некоторые новые тесты, которые используют другие модули, чем предыдущий набор тестов.Или если обновление программного обеспечения устанавливает неисправные библиотеки DLL.Я писал об этом в своем блоге:
Я также обнаружил, что 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');