Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Softwaretests und Qualitätssicherung (https://www.delphipraxis.net/86-softwaretests-und-qualitaetssicherung/)
-   -   Unittest von OnWhatever Events? (https://www.delphipraxis.net/183172-unittest-von-onwhatever-events.html)

Mavarik 17. Dez 2014 16:02

Unittest von OnWhatever Events?
 
Hallo Zusammen!

Wie mache ich ein Unittest von einem OnWhatever Event?
Beispiel:
Delphi-Quellcode:
procedure TestIUDFDatenbank.TestInit;
var
  ClientGUID: TGUID;
begin
  // TODO: Methodenaufrufparameter einrichten
  FIUDFDatenbank.Init(ClientGUID); // Wenn der InitThread fertig ist wird ein Event OnInitDone aufgerufen
  // TODO: Methodenergebnisse prüfen
end;
Wie bringe ich das hier unter, dass ich:
1. Testen kann ob innerhalb von 10 Sekunden der OnInitDone aufgerufen wurde
2. Oder der OnInitFailure

Mavarik

Uwe Raabe 17. Dez 2014 16:08

AW: Unittest von OnWhatever Events?
 
Ich gehe mal davon aus, daß die Events innerhalb des Init-Aufrufs ausgeführt werden. Dann kannst du die Events auf entsprechende Methoden des TestCase setzen, die eine Feld im TestCase setzen, daß du dann nach dem Init prüfst.

Die Zeit kannst du testen, indem du dir den Start von Init merkst und in den jeweiligen Events das Intervall abprüfst.

Für nicht-synchrone Events ist DUnit allerdings gar nicht gut geeignet.

Mavarik 17. Dez 2014 16:35

AW: Unittest von OnWhatever Events?
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1283791)
Dann kannst du die Events auf entsprechende Methoden des TestCase setzen

emm - nochmal für :stupid: bitte...

Zitat:

Zitat von Uwe Raabe (Beitrag 1283791)
Für nicht-synchrone Events ist DUnit allerdings gar nicht gut geeignet.

Oh wie doof...

Die Init läuft in einem Thread und feuert irgendwann den OnXXXX.
Kommt also sofort wieder.
Ich müsste also im TestCase eigentlich einen Anonymen Thread starten der auf das Ergebnis warten kann (5 Sekunden oder was auch immer) um in der Testcase procedure dann true oder false zu erzeugen.

Richig????

Dejan Vu 17. Dez 2014 16:37

AW: Unittest von OnWhatever Events?
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1283791)
...und in den jeweiligen Events das Intervall abprüfst..

Ich würde im Event eher den Aufrufzeitpunkt setzen und im Assert-Teil des Unit-Tests dann das Timing prüfen:

Pseudocode:
Delphi-Quellcode:
// Arrange
unitUnderTest := TMyObject.Create;
unitUnderTest.OnEvent := TestEvent;

StartTime := Now;
EventWasFired := False;
EventTime := 0;
// Act
unitUnderTest.TriggerTheEvent();
// This is nonworking pseudocode but you should get the point
WaitUntil (EventWasFired or (Now-StartTime > maxTimeToWait));

// Assert
Assert.That(EventWasFired , 'The Event was not called');
Assert.That(EventTime-StartTime <= TenSeconds, 'The Event was not called in Time');
...

Procedure TTestCase.TestEvent(Sender : TObject);
Begin
  EventTime := Now;
  EventWasFired := True;
End;
Edit: Du solltest den Event in gar keinem Thread starten. Das ist ja kein Integrationstest, der die 'Blackbox' (Thread und Objekt) testet, sondern nur das Abfeuern des Events.

Uwe Raabe 17. Dez 2014 16:56

AW: Unittest von OnWhatever Events?
 
Zitat:

Zitat von Mavarik (Beitrag 1283796)
Die Init läuft in einem Thread und feuert irgendwann den OnXXXX.
Kommt also sofort wieder.
Ich müsste also im TestCase eigentlich einen Anonymen Thread starten der auf das Ergebnis warten kann (5 Sekunden oder was auch immer) um in der Testcase procedure dann true oder false zu erzeugen.

Besser wäre es, der Code, der im Thread ausgeführt wird, kann direkt geprüft werden. Das käme der Intention eines Unittests eigentlich näher.

Dejan Vu 17. Dez 2014 17:01

AW: Unittest von OnWhatever Events?
 
Beides, oder?

1. Teste den Thread, das er das macht, was er machen soll (z.B. die Objektmethode aufrufen, die einen Event feuern soll. Ob der gefeuert wird, interessiert den Thread ja nicht).
2. Teste das Objekt, das den Event feuert, wenn es soll.

Sir Rufo 17. Dez 2014 17:55

AW: Unittest von OnWhatever Events?
 
Zitat:

Zitat von Dejan Vu (Beitrag 1283802)
Beides, oder?

1. Teste den Thread, das er das macht, was er machen soll (z.B. die Objektmethode aufrufen, die einen Event feuern soll. Ob der gefeuert wird, interessiert den Thread ja nicht).
2. Teste das Objekt, das den Event feuert, wenn es soll.

Ich hätte es jetzt nicht schöner sagen können.

Beim Unittest darf man eben nie aus den Augen verlieren, was man testen möchte. Manchmal benötigt man auch ein paar Dummies zum Testen, denn wer will schon beim Testen einer SEPA-Schnittstelle aus Versehen 100000,00€ überweisen oder per Lastschrift einziehen. ;)

Stevie 17. Dez 2014 20:31

AW: Unittest von OnWhatever Events?
 
Hatte vor einiger Zeit schonmal was in DSharp für async/await in Delphi zusammen gebaut, was mir hier in abgewandelter Form nützlich erschien:

Delphi-Quellcode:
unit Unit1;

interface

uses
  MyDings,
  SyncObjs,
  TestFramework;

type
  TDingsTest = class(TTestCase)
  private
    fSUT: TMyDings;
    fInitDoneEvent: TEvent;
    procedure HandleInitDone(Sender: TObject);
  protected
    procedure SetUp; override;
    procedure TearDown; override;
  published
    procedure OnInitDone_Is_Fired_Within_Ten_Seconds_After_Calling_Init;
  end;

implementation

uses
  Classes,
  Diagnostics,
  Forms,
  Math,
  Windows;

function WaitFor(handle: THandle; timeout: Cardinal): TWaitResult;
var
  handles: array[0..1] of THandle;
  stopwatch: TStopwatch;
begin
  if GetCurrentThreadId = MainThreadID then
  begin
    handles[0] := handle;
    handles[1] := SyncEvent;
    stopwatch := TStopwatch.StartNew;
    repeat
      case MsgWaitForMultipleObjects(2, handles, False, IfThen(timeout = INFINITE,
        INFINITE, timeout - stopwatch.ElapsedMilliseconds), QS_ALLINPUT) of
        WAIT_OBJECT_0: Exit(wrSignaled);
        WAIT_OBJECT_0 + 1: CheckSynchronize;
        WAIT_OBJECT_0 + 2: Application.ProcessMessages;
        WAIT_ABANDONED: Exit(wrAbandoned);
        WAIT_FAILED: Exit(wrError);
      end;
    until stopwatch.ElapsedMilliseconds >= timeout;
    Result := wrTimeout;
  end
  else
    case WaitForSingleObject(handle, timeout) of
      WAIT_OBJECT_0: Result := wrSignaled;
      WAIT_ABANDONED: Result := wrAbandoned;
      WAIT_TIMEOUT: Result := wrTimeout;
    else
      Result := wrError;
    end;
end;

{ TDingsTest }

procedure TDingsTest.HandleInitDone(Sender: TObject);
begin
  fInitDoneEvent.SetEvent;
end;

procedure TDingsTest.OnInitDone_Is_Fired_Within_Ten_Seconds_After_Calling_Init;
begin
  fSUT.Init;
  CheckTrue(WaitFor(fInitDoneEvent.Handle, 10000) = wrSignaled);
end;

procedure TDingsTest.Setup;
begin
  fSUT := TMyDings.Create;
  fSUT.OnInitDone := HandleInitDone;
  fInitDoneEvent := TEvent.Create;
end;

procedure TDingsTest.Teardown;
begin
  fInitDoneEvent.Free;
  fSUT.Free;
end;

initialization
  RegisterTest(TDingsTest.Suite);

end.

Mavarik 17. Dez 2014 21:45

AW: Unittest von OnWhatever Events?
 
Ja das sieht gut aus, Danke!

Muss mir nur noch überlegen, wie und ob ich den produktiven Teil des Init abkoppele oder mit testen soll...
Ich möchte ja ggf. nicht nur die Funktionalität der Procedure Testen, sondern ggf. auf die Daten die hinten raus kommen.
Vielleicht muss ich da noch ein Dummy-Interface mit übergeben, welches die Routinen von der aktiven Datenbank auf ein Testmodel umlenkt..
(Siehe SEPA Beispiel)
Jeremy North hatte da so ein schönes Kreditkartenbeispiel...

Aber ich denke so komme ich erst mal weiter...

Mavarik

Mavarik 19. Dez 2014 13:29

AW: Unittest von OnWhatever Events?
 
Gibt es eine "elegante" Möglichkeit innerhalb des Testforms an zu zeigen, das ein Test noch läuft und nicht abgestürzt ist?

Mavarik


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:04 Uhr.
Seite 1 von 2  1 2      

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