Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Softwaretests und Qualitätssicherung (https://www.delphipraxis.net/86-softwaretests-und-qualitaetssicherung/)
-   -   DUnit - Vorgehensweise (https://www.delphipraxis.net/184190-dunit-vorgehensweise.html)

Klaus01 6. Mär 2015 08:05


DUnit - Vorgehensweise
 
Hallo,

ich habe folgenden Testcase:

Delphi-Quellcode:
  TestTInBuffer = class(TTestCase)
  strict private
    FInBuffer: TInBuffer;
  public
    procedure SetUp; override;
    procedure TearDown; override;
  published
    procedure TestIsEmpty;
    procedure TestAddBuffer;
    procedure TestGetBuffer;
    procedure TestBufferUpperLimit;
    procedure TestBufferLowerLimit;
  end;
Im Testschritt TestAddBuffer füge ich dem fInBuffer einen Buffer hinzu.
Delphi-Quellcode:
procedure TestTInBuffer.TestAddBuffer;
var
  buffer: TBuffer;
begin
  buffer := TBuffer.Create;
  fInBuffer.add(buffer);
  checkEquals(false,fInBuffer.isEmpty);
end;
Im Testschritt TestGetBuffer will ich den Buffer wieder auslesen.
Delphi-Quellcode:
procedure TestTInBuffer.TestGetBuffer;
var
  buffer: TBuffer;
begin
  buffer := fInBuffer.get;
  checkEquals(true, assigned(buffer));
  buffer.Free;
end;
Wenn fInBuffer keinen Buffer enthält - gibt fInBuffer nil als Ergenis zurück.

Der Testschritt schlägt fehl.

Ändere ich den Testschritt so ab:
Delphi-Quellcode:
procedure TestTInBuffer.TestGetBuffer;
var
  buffer: TBuffer;
  buffer1: TBuffer;
begin
  buffer1 := TBuffer.create;
  fInBuffer.add(buffer1);
  buffer := fInBuffer.get;
  checkEquals(true, assigned(buffer));
  buffer.Free;
end;
Dann schägt der Testschritt nicht mehr fehl.

Frage: Warum ist das so? Bleiben Änderungen der Test-Klasse (hier fInBuffer) zwischen den einzelnen Testschritten nicht erhalten?

Grüße
Klaus

Sir Rufo 6. Mär 2015 08:31

AW: DUnit - Vorgehensweise
 
Für jeden Testschritt wird eine neue TestCase-Instanz erstellt.

Und das ist auch gut so, denn was du niemals machen solltest, einen Test-Schritt von einem anderen Test-Schritt abhängig machen.

Wenn dem so sein sollte, dann musst du das auch so schreiben
Delphi-Quellcode:
procedure TestTInBuffer.TestGetBuffer;
var
  buffer: TBuffer;
begin

  TestAddBuffer;

  buffer := fInBuffer.get;
  checkEquals(true, assigned(buffer));
  buffer.Free;
end;

Klaus01 6. Mär 2015 08:34

AW: DUnit - Vorgehensweise
 
.. danke - das Wissen hat mir gefehlt.

Grüße
Klaus

Stevie 6. Mär 2015 22:18

AW: DUnit - Vorgehensweise
 
Ich weiß, dass es sich in der Praxis kaum vermeiden lässt, die Funktionalität einer Methode mit dem Aufruf einer anderen abzuprüfen.
Dennoch sollte man die Interaktion in einem Unittest auf ein Mindestmaß reduzieren.

Im schlimmsten Fall haste nämlich sonst Bugs in 2 Methoden die sich gegenseitig aufheben und deine Tests sind prima grün, aber nix funktioniert.

Jens01 6. Mär 2015 23:04

AW: DUnit - Vorgehensweise
 
Dass man eine Methode mit der anderen testet, ist manchmal sogar notwendig und gewollt. Man muß nur sicher stellen, dass die testende Methode auch getestet ist.

Dejan Vu 7. Mär 2015 10:46

AW: DUnit - Vorgehensweise
 
Die Reihenfolge der Testausführung darf keine Rolle spielen. Wenn du die Add- und Remove-Funktionalität testen willst, dann würde ich den Code duplizieren (in diesem sehr einfachen Fall). Das verstößt zwar gegen DRY, aber im Sinne der Schritte im Test (Arrange-Act-Assert) haben die Arrangements in den beiden Tests nichts miteinander zu tun.

Der Test 'TestGetBuffer' hat sein eigenes 'Arrange'. Zufällig ist das heute identisch mit dem Arrange des 'TestAddBuffer', abe morgen willst du deinen 'TestAddBuffer' vielleicht anders gestalten.

Was ich mir vorstellen kann, sind kleine Arrangement-Methoden, damit der Arrange-Code nicht zu offt dupliziert wird, so etwa:

Delphi-Quellcode:
Function TestTInBuffer.AddSampleToBuffer : TBuffer;
begin
  result := TBuffer.Create;
  fInBuffer.add(result);
end;

procedure TestTInBuffer.TestAddBuffer;
begin
   AddSampleToBuffer;
   checkEquals(false,fInBuffer.isEmpty);
end;

procedure TestTInBuffer.TestGetBuffer;
var
   buffer: TBuffer;

begin
   AddSampleToBuffer;
   buffer := fInBuffer.get;
   checkEquals(true, assigned(buffer));
   buffer.Free;
end;

Sir Rufo 7. Mär 2015 11:07

AW: DUnit - Vorgehensweise
 
Man sollte sich auch von der Vorstellung lösen, dass es pro Klasse auch genau nur einen TestCase geben muss/darf.

Wenn alle Test-Methode den gleichen Ausgangs-Zustand haben müssen, dann wird dieser in der Methode
Delphi-Quellcode:
SetUp
festgelegt. Gibt es jetzt Test-Methoden, die damit nichts anfangen können, dann ist das wohl ein anderer Fall, also gibt es einen neuen TestCase.

Ein TestCase ist (oh Wunder) eine Klasse, mit allem was dazugehört. Die kann man auch ableiten.

Da baut man sich z.B. eine Liste mit Test-Methoden auf und leitet von dieser Klasse ein paar weitere ab, weil man dort per
Delphi-Quellcode:
SetUp
einfach die gleichen Prüfungen auf andere Ausgang-Zustände loslassen möchte. Das könnte ja der Fall sein, wenn ich mehrere Interface-Implementierungen testen möchte. Die Tests sind die gleichen nur die konkreten Implementierungen eben nicht.
Delphi-Quellcode:
TTestIFoo = class( TTestCase )
private
  Foo : IFoo;
published
  procedure TestFoosBar; // testet das Interface
end;

TTestIFoo_TSimpleFoo = class( TTestIFoo )
protected
  procedure SetUp;
end;

procedure TTestIFoo_TSimpleFoo.SetUp;
begin
  Foo := TSimpleFoo.Create(); // erzeugt das Interface
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:03 Uhr.

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