CheckException akzeptiert nur 0-Parameter-Verfahren; Wie teste ich, dass andere Methoden Ausnahmen auslösen?

StackOverflow https://stackoverflow.com/questions/4613152

Frage

Ich frage mich, was ist die beste Praxis-Test für Ausnahmen in dunit. Ich bin nicht sehr vertraut mit Methodenzeiger in Delphi. Gibt es eine Möglichkeit zu binden Argumente ein Verfahren Zeiger, so dass es ohne Argumente geltend gemacht werden könnten. Im Moment schreibe ich immer ein zusätzliches Verfahren, das tut dies ‚verbindlich‘ manuell. Das wird ärgerlich sein, wenn das SUT viel werfen Methoden hat.

// What i did before i knew abput CheckExcepion
procedure MyTest.MyMethod_BadInput_Throws;
var
    res: Boolean;
begin
    res := false;
    try
        sut.MyMethod('this is bad');
    except
        on e : MyExpectedException do:
            res := true;
    end;
    CheckTrue(res);
end;

// What i do now
procedure MyTest.MyMethodWithBadInput;
begin
    sut.MyMethod('this is bad');
end;

procedure MyTest.MyMethod_BadInput_Throws;
begin
    CheckException(MyMethodWithBadInput, MyExpectedException);
end;

// this would be nice
procedure MyTest.MyMethod_BadInput_Throws;
begin
    CheckException(
        BindArguments(sut.MyMethod, 'this is bad'),  // <-- how to do this
        MyExpectedException);
end;
War es hilfreich?

Lösung

Sie können StartExpectingException verwenden, um Ihren Ihren Methodenaufruf zu umgeben).

StartExpectingException(MyException);
MyMethod(MyParam);
StopExpectingException();

Andere Tipps

Ich weiß nicht, ob DUnit es noch unterstützt, aber dies ist ein perfekter Anwendungsfall für anonyme Methoden, die 2010 in Delphi eingeführt wurden Wenn DUnit nicht unterstützt, dann können Sie bequem die Quelle selbst ändern.

Wie bereits erwähnt, ist dies ein großartiger Ort für anonyme Methoden.

Hier ist, wie ich es tun. I "ausgeliehen" diese von Alex Ciobanu:

procedure TestTMyClass.CheckException(aExceptionType: TClassOfException; aCode: TTestCode; const aMessage: String);
var
  WasException: Boolean;
begin
  WasException := False;
  try
    aCode;
  except
    on E: Exception do
    begin
      if E is aExceptionType then
      begin
        WasException := True;
      end;
    end;
  end;
  Check(WasException, aMessage);
end;

Dann rufen Sie es mit so etwas wie:

CheckException(ETestingException, 
             procedure begin FMyClass.RaiseTestingException end,      
             'The ETestingException exception didn''t get raised.  That is impossible!');

Um die Verwendung StartExpectingException() ist nicht der beste Weg, falls Sie testen möchten mehr als eine Ausnahmefällen. Um alle möglichen Fälle in meinem Testverfahren zu testen, zusammen mit Ausnahmen verwende ich diesen Algorithmus:

uses
  Dialogs;
procedure MyTest.MyMethod_Test;
begin
  // Test for Exceptions
  try
    MyMethod(MyParam1CreatingException1);
    ShowMessage('Error! There should have been exception: Exxx here!');
    Check(false);
  except on E: Exception do Check(E is  ExceptionType1); end; // This exception is OK
  try
    MyMethod(MyParam2CreatingException2);
    ShowMessage('Error! There should have been exception: Exxx here!');
    Check(false);
  except on E: Exception do Check(E is  ExceptionType2); end; // This exception is OK
  // ... test other exceptions ...

  // Test other parameters
  CheckEquals('result1', MyMethod(MyParam1));
  CheckEquals('result2', MyMethod(MyParam2));
  // ... other tests ...
end;

Der Grund, warum ich ShowMessage('Error! There should be exception: Exxx here!'); anstelle der bereitgestellten Check(false, 'There should have been an EListError.'); Methode besteht darin, dass in meinem Fall (Delphi6) die Check(boolean, 'Message') funktioniert nicht - es ist nicht die Nachricht, falls nicht zeigen, dass Check ist innerhalb try...except Block (weiß nicht warum).

Dies ist die Arbeits- und verbesserte Version von Nick Hodges' Antwort, die Unterklassen DUnit der TestFramework.TTestCase:

uses
  TestFramework, System.SysUtils;
type
  TTestCode = reference to procedure;

  TTestCasePlus = class(TestFramework.TTestCase)
    procedure CheckException(
      ExceptionType: TClass; Code: TTestCode; const Message: String = '');
  end;

implementation

procedure TTestCasePlus.CheckException(
  ExceptionType: TClass; Code: TTestCode; const Message: String = '');
{ Check whether some code raises a specific exception type.

Adapted from http://stackoverflow.com/a/5615560/797744

Example:

  Self.CheckException(EConvertError,
                      procedure begin UnformatTimestamp('invalidstr') end);

@param ExceptionType: The exception class which we check if it was raised.
@param Code: Code in the form of an anonymous method that should raise the
  exception.
@param Message: Output message on check failure. }
var
  WasRaised: Boolean;
begin
  WasRaised := False;
  try
    Code;
  except
    on E: Exception do
      if E is ExceptionType then
        WasRaised := True;
  end;
  Check(WasRaised, Message);
end;

Ein schöner Bonus dieser Methode zu überprüfen, ob eine Ausnahme über Start/StopExpectingException() angehoben wurde, ist, dass Sie die testrunner im Debug-Build ausgeführt werden kann, und es wird nicht halten Sie stört mit „Exception ausgelöst wurde. Pause? Weiter?“ jedes Mal, wenn eine Ausnahme ausgelöst wird -. obwohl es behandelt wurde

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top