AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

Massentests mit DUnitX

Ein Thema von manumeter44 · begonnen am 19. Mär 2021 · letzter Beitrag vom 20. Mär 2021
Antwort Antwort
Seite 1 von 2  1 2   
manumeter44

Registriert seit: 19. Mär 2021
1 Beiträge
 
#1

Massentests mit DUnitX

  Alt 19. Mär 2021, 07:55
Schönen guten Tag zusammen,
ich bin gerade dabei mich in DUnitX einzuarbeiten und frage mich, ob es in diesem Test-Framework von Delphi möglich ist Massentests ohne ewig langen Code hinzubekommen.

Beispiel:
Ich habe eine Funktion vorliegen welche einfach nur 2 Werte, die als Eingangsparameter mitgegeben werden addieren soll:
function TCalc.Add(x, y: Real): Real;
begin
Result := x + y;
end;

Und diese Funktion soll nun nicht mit "nur" 2 [TestCase] auf ihre Richtigkeit hin überprüft werden sondern mehrere Male.Ich stelle mir das etwa so vor:
[Test]
[TestCase('Add Test','0,0,0')]
[TestCase('Add Test','0,1,1')]
[TestCase('Add Test','0,2,2')]
[TestCase('Add Test','0,3,3')]
[TestCase('Add Test','0,4,4')]
.
.
.
.
.
[TestCase('Add Test','10,10,20')]
procedure TestAdd(Value1, Value2, Expected: Real);

Die Frage, die sich mir nun stellt ist: Wie ist es möglich (wie oben drüber dargestellt) so viele Testfälle darzustellen ohne diese explizit einzeln zu definieren? Kann man TestCases irgendwie durchloopen oder eine andere Möglichkeit sich bei "Massentests" im Code kurz zu halten?
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.024 Beiträge
 
Delphi 10.3 Rio
 
#2

AW: Massentests mit DUnitX

  Alt 20. Mär 2021, 06:10
Wie wäre es mit...


Delphi-Quellcode:
begin
  for I:=0 to 1000 do
    begin
      if Add(A,B) <> C then
        begin
          Assert.Fail;
          exit;
        end;
   end;
   Assert.Pass;
end;
Und A und B kannst Du dann entsprechen vorgeben, errechnen.. was auch immer
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
8.591 Beiträge
 
Delphi 10.4 Sydney
 
#3

AW: Massentests mit DUnitX

  Alt 20. Mär 2021, 09:55
Der Nachteil bei dem Ansatz mit der for-Schleife ist, dass der Test beim ersten Fehler abbricht und Fehler in höheren Schleifendurchgängen erst entdeckt werden, wenn der Fehler behoben wurde. Aus diesem Grund wurden ja überhaupt dieses TestCase-Attribut erfunden.

Man kann das aber auch mit einem TestDataProvider lösen (hier zur Übersicht alles in einer Unit):
Delphi-Quellcode:
unit TestUnit1;

interface

uses
  DUnitX.Types, DUnitX.InternalDataProvider, DUnitX.TestDataProvider, DUnitX.TestFramework;

type
  TCalcSourceProvider = class(TTestDataProvider)
  private
    FMaxTest: Integer;
  public
    constructor Create; override;
    function GetCaseCount(const methodName: string): Integer; override;
    function GetCaseName(const methodName: string): string; override;
    function GetCaseParams(const methodName: string; const caseNumber: Integer): TValueArray; override;
  end;

type
  [TestFixture]
  TCalcTestObject = class
  public
    [Test]
    [TestCaseProvider(TCalcSourceProvider)] // alternativ auch: [TestCaseProvider('CalcSourceProvider')] (siehe initialization)
    procedure TestAdd(Value1, Value2, Expected: Double);
  end;

implementation

constructor TCalcSourceProvider.Create;
begin
  inherited;
  FMaxTest := 11*11;
end;

function TCalcSourceProvider.GetCaseCount(const methodName: string): Integer;
begin
  Result := FMaxTest;
end;

function TCalcSourceProvider.GetCaseName(const methodName: string): string;
begin
  Result := methodName;
end;

function TCalcSourceProvider.GetCaseParams(const methodName: string; const caseNumber: Integer): TValueArray;
var
  A: Double;
  B: Double;
begin
  A := caseNumber div 11;
  B := caseNumber mod 11;
  Result := TValueArray.Create(A, B, A + B);
end;

procedure TCalcTestObject.TestAdd(Value1, Value2, Expected: Double);
begin
  { Hier testen wir erstmal, ob unser Dataprovider überhaupt funktioniert. Wenn das klappt, ersetzen wir das mit dem Test der TCalc-Methode Add }
  Assert.AreEqual(Expected, Value1 + Value2, 0.1);
end;

initialization
  TestDataProviderManager.RegisterProvider('CalcSourceProvider', TCalcSourceProvider);
  TDUnitX.RegisterTestFixture(TCalcTestObject);
end.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von Bernhard Geyer
Bernhard Geyer

Registriert seit: 13. Aug 2002
16.880 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: Massentests mit DUnitX

  Alt 20. Mär 2021, 11:53
Der Nachteil bei dem Ansatz mit der for-Schleife ist, dass der Test beim ersten Fehler abbricht und Fehler in höheren Schleifendurchgängen erst entdeckt werden, wenn der Fehler behoben wurde. Aus diesem Grund wurden ja überhaupt dieses TestCase-Attribut erfunden.
Wenn man solche Tests hat, sollte die SW-(Version/Hotfix/Release) erst freigegeben werden wenn keine der Tests fehl schlagen.
D.h. dieser Schleifen-Ansatz hätte für die Veröffentliche SW-Version keinen Nachteil.

Und diese Schleifenansatz hat den Vorteil das man eine großen Menge an Fällen testen kann. Das alles in tausenden Zeilen Attribute zu schreiben kostet nur zeit das zu schreiben.
Der Attribut-Weg ist ja Fälle gedacht, in denen ich spezielle Werte testen will, aber nicht eine ganzen größeren Block.
Windows Vista - Eine neue Erfahrung in Fehlern.
  Mit Zitat antworten Zitat
Rollo62

Registriert seit: 15. Mär 2007
3.182 Beiträge
 
Delphi 10.4 Sydney
 
#5

AW: Massentests mit DUnitX

  Alt 20. Mär 2021, 12:18
Die Frage ist doch auch woher die Testdaten dann eigentlich kommen.
Eine vorgegebene Tabelle, empirische Daten, per Zufall, oder gibt es sogar eine Formel ?

Ich bin prinzipiell etwas gegen vorgegebene Tabellen, denn damit ist meist die Idee des Testers verbunden, und seltene Fälle werden nie erkannt.
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.024 Beiträge
 
Delphi 10.3 Rio
 
#6

AW: Massentests mit DUnitX

  Alt 20. Mär 2021, 14:42
Uwe's Ansatz mit dem Provider finde ich richtig gut (+1) - kannte ich noch nicht - aber "meine" Schleife reicht mir in der Regel..
Wenn ein Unittest fehl schlägt, dann fixe ich diesen... Wenn mir Testinsight anzeigt das 1000 fehlgeschlagen sind, hilft mir das nicht weiter,
sondern frustriert eher. I.d.R. fixed man doch einen Fehler nach dem anderen.

Wobei ich keinen Sinn darin sehe 1+1 1+2 1+3 1+4 und so weiter zu testen...
Das ist ein Computer, wenn er 1+1 rechnen kann, kann er auch 1+n rechnen. Es geht doch dann eher um die Corner-Cases... 1+0 1+-1 1+65568 1+0.5 oder was auch immer...

Mavarik
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
3.824 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#7

AW: Massentests mit DUnitX

  Alt 20. Mär 2021, 14:53
Wenn mir Testinsight anzeigt das 1000 fehlgeschlagen sind, hilft mir das nicht weiter
Wenn halt 1000 Tests fehlschlagen, dann sind 1000 Tests auch wieder grün, wenn du den Fehler fixt.

Der Witz ist aber, dass in den schlimmen Fällen der Code nur für eine bestimmte Kombination fehlschlägt.
Das ist weitaus hilfreicher als wenn der Test mit der Schleife einfach nur fehlschlägt.
Wenn du nämlich dann noch eine genaue Fehlermeldung ausgeben willst, mit welchen Werten das fehlgeschlagen ist, musste wieder unnötigen Code schreiben.

Leider benamt DUnitX die Tests, die über den TestDataProvider erzeugt werden ein bisschen lame - mit meiner Implementierung in Spring.Testing siehst du genau, mit welchen Werten der Test aufgerufen wurde.

Ein Beispiel, wie man sehr einfach Mengen von werten in einen Unittest stopfen kann, hab ich hier mal skizziert, um eine Funktion für die Primfaktorzerlegung zu testen. Unten kann man sehen, wie das dann im TestInsight (und auch wenn man das mit der oldschool DUnit GUI ausführen würde) ausschaut.

Ich kann dann genau den Test anhaken, der da fehlschlägt, und debuggen, ohne erst durch irgendne Schleife zu müssen und nen conditional Breakpoint zu setzen, der erst stoppt wenn der Wert kommt, der den Test fehlschlagen lässt, alles mühsamer Mist.


Im übrigen ist der Ansatz, die Testdaten von extern zu bekommen gar nicht mal so abwegig, das nennt sich dann zum Beispiel "data driven testing" - da kann man tolle Sachen mit machen - natürlich in ganz anderem Ausmaße und nicht um nen Taschenrechner zu testen - obwohl, eigentlich braucht man fürn Taschenrechner bloß eine Testfunktion, die dann als Input die Formel hereinbekommt, die man eingetippt hat und das erwartete Ergebnis - und das kann man hervorragend in einer Textdatei oder so pflegen.
Miniaturansicht angehängter Grafiken
testdataprovider.png  
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight

Geändert von Stevie (20. Mär 2021 um 15:14 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
8.591 Beiträge
 
Delphi 10.4 Sydney
 
#8

AW: Massentests mit DUnitX

  Alt 20. Mär 2021, 15:38
Und diese Schleifenansatz hat den Vorteil das man eine großen Menge an Fällen testen kann. Das alles in tausenden Zeilen Attribute zu schreiben kostet nur zeit das zu schreiben.
Eben dafür gibt es ja auch den TestDataProvider.

Im übrigen ist der Ansatz, die Testdaten von extern zu bekommen gar nicht mal so abwegig, das nennt sich dann zum Beispiel "data driven testing" - da kann man tolle Sachen mit machen
In der Tat! Ich benutze das z.B. für die Parser-Tests bei MMX. Die Testdaten sind ja in der Regel Code-Schnipsel oder ganze Units. Mit einem TestDataProvider, der einfach die Dateien in einem Verzeichnis auflistet, brauche ich nur eine neue Datei in das entsprechende Verzeichnis zu legen und schon laufen alle Tests auch mit dem neuen Code-Schnipsel - ohne dass ich das Testprojekt überhaupt neu compilieren muss. Das ist ganz praktisch, wenn man als Folder das Source-Verzeichnis von Delphi angibt. Da kommen schon mal ein paar Dateien zusammen.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.024 Beiträge
 
Delphi 10.3 Rio
 
#9

AW: Massentests mit DUnitX

  Alt 20. Mär 2021, 15:47

Wenn halt 1000 Tests fehlschlagen, dann sind 1000 Tests auch wieder grün, wenn du den Fehler fixt.

Der Witz ist aber, dass in den schlimmen Fällen der Code nur für eine bestimmte Kombination fehlschlägt.
Das ist weitaus hilfreicher als wenn der Test mit der Schleife einfach nur fehlschlägt.
Wenn du nämlich dann noch eine genaue Fehlermeldung ausgeben willst, mit welchen Werten das fehlgeschlagen ist, musste wieder unnötigen Code schreiben.
Wie gesagt ich kannte das nicht, daraus ergeben sich aber unzählige neue Möglichkeiten einige meiner Tests zu optimieren...
  Mit Zitat antworten Zitat
Benutzerbild von Bernhard Geyer
Bernhard Geyer

Registriert seit: 13. Aug 2002
16.880 Beiträge
 
Delphi 10.4 Sydney
 
#10

AW: Massentests mit DUnitX

  Alt 20. Mär 2021, 16:14
Wobei ich keinen Sinn darin sehe 1+1 1+2 1+3 1+4 und so weiter zu testen...
Macht sinn z.B. einen (langsamen) Algorithmus/Implementierung A durch einen Algorithmus/Implementierung B zu ersetzen.
Da macht es dann sinn möglich einen großen Teil der möglichen Input/Output-Kombinationen zu prüfen.
Windows Vista - Eine neue Erfahrung in Fehlern.
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +2. Es ist jetzt 01:45 Uhr.
Powered by vBulletin® Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf