Comparaison des problèmes dans les contrôles DUnit CheckEquals avec les valeurs du champ monétaire
Question
Je compare certaines valeurs de devise dans DUnit, mais cela ne fonctionne pas du tout sur ma machine (fonctionne sur d'autres, mais pas sur la mienne).
Un exemple:
CheckEquals(16.65, SomeCurrencyFieldValue);
Élève:
expected: <16,65> but was: <16,65>
si la comparaison suivante fonctionne, alors:
var
Temp: Currency;
begin
Temp := 16.65;
CheckEquals(Temp, SomeCurrencyFieldValue);
La question qui se pose est la suivante: pourquoi la comparaison ne fonctionne-t-elle pas lorsque je passe directement la valeur à la méthode CheckEquals?
La solution
Le problème est lié à la manière dont Currency
les valeurs sont converties en Extended
valeurs au moment de l'exécution par rapport au mode de conversion des littéraux à virgule flottante en CheckEquals
valeurs au moment de la compilation. Si la conversion n’est pas la même dans les deux cas, les valeurs transmises à Double
peuvent ne pas être équivalentes.
Il serait utile de vérifier dans la fenêtre de la CPU du débogueur si l'une ou l'autre des valeurs passe par une valeur <=> intermédiaire avant de se rendre à <=> en préparation de l'appel de fonction. Une conversion supplémentaire affecterait la valeur exacte du résultat.
Une autre chose à considérer est que 16.65 n'est pas représentable exactement comme une <=> valeur, mais est exactement comme une <=> valeur. Bien que <=> soit classé en tant que type à virgule flottante, il s’agit en réalité d’un nombre entier 64 bits mis à l’échelle en points fixes. C’est probablement une raison pour demander une <=> surcharge supplémentaire dans DUnit tenant compte de cela.
Autres conseils
Je vois qu'il n'y a que CheckEquals () pour les valeurs étendues dans les sources Delphi 2007 dUnit. Mais vous pouvez utiliser celui-ci:
procedure CheckEquals(expected, actual: extended; delta: extended;
msg: string = ''); overload; virtual;
et donnez un delta approprié aux valeurs monétaires.
J'ai rencontré le même problème. Il semble que certaines DLL modifient un mot de contrôle FPU (processeur). Cela explique pourquoi l'erreur ne se produit pas toujours. Il peut apparaître soudainement lorsque de nouveaux tests, qui utilisent d'autres unités que la suite de tests précédente, sont ajoutés. Ou si une mise à jour logicielle installe de mauvaises DLL. J'ai écrit sur mon blog:
J'ai également constaté que Delphi contient une fonction SafeLoadLibrary, qui restaure le mot de contrôle.
Cela explique également pourquoi la question initiale indique que le problème dépend de la machine.
voici une solution suggérée:
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;
Je connais sa mauvaise implémentation, mais c'est juste une idée, que j'aime mieux que & "; delta &"; et beaucoup plus facile à utiliser.
Dans la version actuelle de dunit, vous pouvez utiliser
procedure CheckEquals(expected, actual: extended; delta: extended; msg: string = ''); overload; virtual;
CheckEquals(0.011,0.01,0.009,'will pass');