Vergleicht man Probleme in DUnit CheckEquals mit Währungsfeldwerte
Frage
Ich habe einige Währungswerte in DUnit zu vergleichen, aber es ist überhaupt nicht auf meinem Rechner arbeitet (Arbeit auf anderen, aber nicht auf mich).
Ein Beispiel:
CheckEquals(16.65, SomeCurrencyFieldValue);
Hebt:
expected: <16,65> but was: <16,65>
, wenn die nach dem Vergleich tut dann funktioniert:
var
Temp: Currency;
begin
Temp := 16.65;
CheckEquals(Temp, SomeCurrencyFieldValue);
Die Frage ist: Warum der Vergleich nicht, wenn ich den Wert direkt an die CheckEquals Methode übergeben
Lösung
Das Problem hat mit, wie Currency
Werten zu tun bekommen gewandelten Werte zur Laufzeit im Vergleich zu Extended
wie Gleitpunktliterale konvertiert werden Werten bei der Kompilierung Extended
. Wenn die Umwandlung nicht die in beiden Fällen gleich ist, dann sind die zu CheckEquals
gebenen Werte nicht gleich vergleichen.
Es würde sich lohnen, in dem Debugger Fenster CPU überprüft, ob eine der beiden Werte durch einen Zwischen Double
Wert auf seinem Weg geht in der Vorbereitung für den Funktionsaufruf Extended
. Eine zusätzliche Umwandlung, den genauen Wert des Ergebnisses beeinflussen würde.
Eine andere Sache zu prüfen ist, dass 16,65 nicht genau darstellbar als Extended
Wert, aber es ist darstellbare genau als Currency
Wert. Obwohl Currency
als Fließkommatyp klassifiziert wird, ist es wirklich ein Festpunkt-skalierten ganzzahligen 64-Bit. Das ist wahrscheinlich ein Grund für eine zusätzliche CheckEquals
Überlastung in DUnit anfordert, die berücksichtigt, dass.
Andere Tipps
Ich sehe, dass es nur CheckEquals ist () für längere Werte in den Delphi 2007 dunit Quellen. Aber man könnte diese verwenden:
procedure CheckEquals(expected, actual: extended; delta: extended;
msg: string = ''); overload; virtual;
und gibt eine richtige Delta für Währungswerte.
Ich traf das gleiche Problem. Es sieht aus wie einige DLLs eine FPU (Prozessor) Steuerwort ändern. Dies erklärt, warum tritt der Fehler nicht immer auftreten. Es kann plötzlich auftreten, wenn einige neue Tests, die anderen Einheiten als der vorherige Test-Suite verwenden, hinzugefügt werden. Oder wenn eine Software-Update installiert schlechten DLLs. Ich habe auf meinem Blog darüber geschrieben:
Ich fand auch, dass Delphi eine SafeLoadLibrary Funktion enthält, die das Steuerwort wieder her.
Dies erklärt auch, warum die ursprüngliche Frage erwähnt, dass das Problem ist maschinenabhängig.
Hier ist eine vorgeschlagene Lösung:
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;
Ich weiß, dass seine schlechte Umsetzung, aber nur eine Idee, dass ich besser als „delta“ mag, und viel einfacher zu bedienen.
In der aktuellen Version von dunit können Sie
procedure CheckEquals(expected, actual: extended; delta: extended; msg: string = ''); overload; virtual;
CheckEquals(0.011,0.01,0.009,'will pass');