CheckException accetta solo metodi con 0 parametri;come posso verificare che altri metodi lancino eccezioni?
-
26-09-2019 - |
Domanda
Mi chiedo quale sia la procedura migliore per verificare le eccezioni in dunit.Non ho molta familiarità con i puntatori di metodo in Delphi.Esiste la possibilità di associare argomenti a un puntatore al metodo in modo che possa essere invocato senza argomenti.Al momento scrivo sempre un metodo aggiuntivo che esegue manualmente questo "associazione".Questo sarà fastidioso se il SUT ha molti metodi di lancio.
// 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;
Soluzione
È possibile utilizzare StartExpectingException
per circondare il vostro il vostro chiamata al metodo).
StartExpectingException(MyException);
MyMethod(MyParam);
StopExpectingException();
Altri suggerimenti
Non so se dunit sostiene ancora, ma questo è un caso d'uso perfetto per i metodi anonimi, che sono stati introdotti in Delphi 2010. Se dunit non supporta allora si può facilmente modificare il sorgente da soli.
Come ha fatto notare, questo è un luogo ideale per i metodi anonimi.
Ecco come lo faccio. I "preso in prestito" da questo 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;
Poi lo chiamano con qualcosa di simile:
CheckException(ETestingException,
procedure begin FMyClass.RaiseTestingException end,
'The ETestingException exception didn''t get raised. That is impossible!');
Per l'uso StartExpectingException()
non è il modo migliore nel caso in cui si desidera testare più di un caso di eccezione. Al fine di testare tutti i casi possibili nella mia procedura di prova, insieme con le eccezioni che uso questo algoritmo:
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;
Il motivo per cui io uso ShowMessage('Error! There should be exception: Exxx here!');
invece del metodo Check(false, 'There should have been an EListError.');
fornita è che nel mio caso (Delphi6) il Check(boolean, 'Message')
non funziona - non mostra il messaggio nel caso in cui Check è blocco try...except
all'interno (non so perché).
Questa è la versione funzionante e migliorata della risposta di Nick Hodges, che sottoclassa quella di DUnit 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;
Un bel vantaggio per questo metodo di verifica se è stata sollevata un'eccezione Start/StopExpectingException()
è che puoi eseguire il testrunner nella build di debug e non continuerà a disturbarti con "È stata sollevata un'eccezione.Rottura?Continuare?" ogni volta che viene sollevata un'eccezione, anche se è stata gestita.