Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi [DUnit] Test für Double Property schlägt fehl (https://www.delphipraxis.net/131541-%5Bdunit%5D-test-fuer-double-property-schlaegt-fehl.html)

Zwoetzen 26. Mär 2009 09:13


[DUnit] Test für Double Property schlägt fehl
 
Hi DP'ler,

habe mich nun mal mit DUnit vertraut gemacht, und finde das ganze recht hilfreich ^^
Doch ich stehe vor einem Problem, was ich nicht nachvollziehen kann:

Ich habe eine Klasse, die einen Double-Wert als Property hat:
Delphi-Quellcode:
type
  TMyObjet = class(TObject)
  private
    FD: Double;
    procedure SetD(const Value: Double);
  public
    property D: Double read FD write SetD;
  end;

[...]

procedure TMyObjet.SetD(const Value: Double);
begin
  FD := Value;
end;
Der dazugehörige, sehr einfache Test schlägt allerdings schon fehl:
Delphi-Quellcode:
type
  TestMyObject = class(TTestCase)
  strict private
    FMyObject: TMyObject;
  protected
    procedure SetUp; override;
    procedure TearDown; override;
  published
    procedure TestDouble;
  end;

[...]

procedure TestMyObject.TestDouble;
begin
  FMyObject.D := 1.23;
  CheckEquals(1.23, FMyObject.D, 'Wrong Value of D');
end;
Wenn ich den Test nun ausführe, bekomme ich die Meldung:
Code:
TestDouble: ETestFailure
at $004A3FED
Wrong Value of D, expected: <1,23> but was: <1,23>
Kann mir jemand den Fehler sagen? Denn die Zuweisung des Doubles sollte eigentlich korrekt sein (da passiert ja eigentlich nix ^^), nur der Test schlägt eben fehl, was mich verwundert. (Die Meldung selbst sagt ja, dass (korrekterweise) 1.23 vorhanden war, aber wieso gibt es trotzdem ein ETestFailure?)

MfG Zwoetzen

jfheins 26. Mär 2009 09:33

Re: [DUnit] Test für Double Property schlägt fehl
 
Fließkommazahlen nie direkt vergleichen ;)

Aufgrund der binären representation ist 1,23 nicht immer exakt 1,23 sondern vll. einmal 1,2299999999999312354 und einmal 1,23000000036737 ;)

Zwoetzen 26. Mär 2009 09:52

Re: [DUnit] Test für Double Property schlägt fehl
 
Danke für die schnelle Antwort, das war der entscheidende Hinweis ;)

Mit folgendem Code geht es jetzt :)

Delphi-Quellcode:
procedure TestMyObject.TestDouble;
var
  Temp: Double;
begin
  FMyObject.D := 4.56;
  Temp := 4.56;
  CheckEquals(Temp, FMyObject.D, 'Wrong Value of D');
end;
Im späteren Programm wird ja dann sowieso alles über Variablen gehen, da passiert mir sowas hoffentlich nicht mehr :mrgreen:


Was mich nur jetzt noch verwundert: Der Debugger selbst zeigt wieder "1.23" als Wert an, müsste er dann nicht auch die leicht abweichenden Werte anzeigen? Oder erkennt er, dass es eigentlich 1.23 sein müsste (oder rundet einfach) und zeigt deshalb den richtigen Wert? :gruebel:

Lemmy 26. Mär 2009 10:26

Re: [DUnit] Test für Double Property schlägt fehl
 
hi,

Zitat:

Zitat von Zwoetzen
Danke für die schnelle Antwort, das war der entscheidende Hinweis ;)

Mit folgendem Code geht es jetzt :)
...
Im späteren Programm wird ja dann sowieso alles über Variablen gehen, da passiert mir sowas hoffentlich nicht mehr :mrgreen:

mir scheint du hast nicht wirklich verstanden, was jfheins versucht hat zu sagen. Lies dir sein Posting nochmal durch und preise dein Glück, dass dir ein schöner Treffer gelungen ist.
Schau dir in dem Zusammenhang die CompareValue-Funktion aus der Unit math an, die wird dir bei deinem Problem helfen können...

Grüße
Lemmy

Zwoetzen 26. Mär 2009 11:05

Re: [DUnit] Test für Double Property schlägt fehl
 
Jetzt hast du mich komplett verwirrt...

Wenn ich den Wert vorher an einen Double zuweise, dann müsste er doch auch die Double-Ungenauigkeit bekommen, oder nicht? Und somit müssten beim Vergleich der beiden Doubles wieder die gleichen Werte sein :gruebel:

Lemmy 26. Mär 2009 11:21

Re: [DUnit] Test für Double Property schlägt fehl
 
Hi,

ich gebe zu, dass ich den Sinn deines beispielhaften Unittests nicht ganz verstehe, gehe aber einfach mal davon aus, dass Du im späteren Betrieb nicht nur eine Wertzuweisung prüfen willst, sondern dass einer der Floats aus einer Berechnung kommt. Und spätestens dann erleidest Du Schiffbruch. Deshalb gibts zumindest für mich 2 eiserne Regeln:
1. Verwende keine Floats wo Currency verwendet werden kann (4 Nachkommastellen reichen (d.h. eine maximale Genauigkeit von 3 Stellen nach dem Komma!) + Wertebereich reicht aus)
2. Vergleiche niemals 2 Floats direkt, sondern immer mit der CompareValue-Funktion.

Das bedeutet vielleicht das eine oder andere mal einen etwas höheren Aufwand, ich weiß aber eins: das kann nicht aufgrund der Float-Ungenauigkeiten irgend wann mal schief laufen, weil irgend jemand eine Methode, eine Klasse, eine Funktion nicht genau so einsetzt wie du es dir gedacht hast.

Grüße
Lemmy

Zwoetzen 26. Mär 2009 12:26

Re: [DUnit] Test für Double Property schlägt fehl
 
Stimmt, da hast du auch wieder recht. Anfangs war der Test schon komplexer, hatte ihn dann aber vereinfacht, um das Problem zu finden. Und am Ende ist das Double alleine übrig geblieben ^^

Deine 2 Regeln werde ich nun auch befolgen, um solche (unnötigen) Probleme zu umgehen. :)
(Im aktuellen Projekt greift 1., da ich (zufälligerweise) mit 3 Stellen arbeite ^^)

Danke für eure Antworten :)

mjustin 26. Mär 2009 13:46

Re: [DUnit] Test für Double Property schlägt fehl
 
Zitat:

Zitat von Zwoetzen
Delphi-Quellcode:
procedure TestMyObject.TestDouble;
begin
  FMyObject.D := 1.23;
  CheckEquals(1.23, FMyObject.D, 'Wrong Value of D');
end;

DUnit enthält auch eine passende CheckEquals Methode für diesen Fall:
Delphi-Quellcode:
procedure CheckEquals(expected, actual: extended; delta: extended; msg: string = ''); overload; virtual;
Einfach das Delta noch angeben, das maximal erlaubt ist.
Delphi-Quellcode:
procedure TestMyObject.TestDouble;
begin
  CheckEquals(1.23, FMyObject.D, 0.0001, 'Wrong Value of D');
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:30 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz