La comparación de las cuestiones en DUnit CheckEquals con la Moneda de los Valores de Campo
Pregunta
Estoy comparando algunos de los valores de moneda en DUnit pero no funciona en mi máquina (trabajo en otros, pero no en la mía).
Un ejemplo:
CheckEquals(16.65, SomeCurrencyFieldValue);
Plantea:
expected: <16,65> but was: <16,65>
si hacer la siguiente comparación, a continuación, funciona:
var
Temp: Currency;
begin
Temp := 16.65;
CheckEquals(Temp, SomeCurrencyFieldValue);
La pregunta es:¿Por qué la comparación no funciona cuando se me pase el valor directo a la CheckEquals método?
Solución
El problema tiene que ver con cómo Currency
los valores se convierten en Extended
los valores en tiempo de ejecución frente a cómo de punto flotante literales se convierten en Extended
los valores en tiempo de compilación.Si la conversión no es el mismo en ambos casos, los valores pasan a CheckEquals
no pueden comparar la igualdad.
Sería digno de la comprobación en el depurador de la CPU de la ventana si cualquiera de los valores pasa a través de un intermedio Double
valor en su camino a Extended
en la preparación para la llamada a la función.Una conversión adicional podría afectar el valor exacto del resultado.
Otra cosa a considerar es que 16.65 no es representable exactamente como un Extended
valor, pero es puede representarse exactamente como un Currency
valor.Aunque Currency
se clasifica como un tipo de punto flotante, es realmente un punto fijo a escala entero de 64 bits.Probablemente ese sea el motivo para solicitar una nueva CheckEquals
sobrecarga en DUnit que toma eso en cuenta.
Otros consejos
Veo que solo hay CheckEquals () para valores extendidos en las fuentes dUnit de Delphi 2007. Pero podrías usar este:
procedure CheckEquals(expected, actual: extended; delta: extended;
msg: string = ''); overload; virtual;
y proporcione un delta apropiado para los valores de moneda.
Encontré el mismo problema. Parece que algunas DLL modifican una palabra de control de FPU (procesador). Esto explica por qué el error no ocurre siempre. Puede aparecer repentinamente cuando se agregan algunas pruebas nuevas, que usan otras unidades que el conjunto de pruebas anterior. O si una actualización de software instala archivos DLL incorrectos. He escrito sobre en mi blog:
También descubrí que Delphi contiene una función SafeLoadLibrary, que restaura la palabra de control.
Esto también explica por qué la pregunta original menciona que el problema depende de la máquina.
aquí hay una solución sugerida:
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;
Sé que su implementación es mala, pero es solo una idea, que me gusta más que " delta " ;, y mucho más fácil de usar.
En la versión actual de dunit puede usar
procedure CheckEquals(expected, actual: extended; delta: extended; msg: string = ''); overload; virtual;
CheckEquals(0.011,0.01,0.009,'will pass');