delphi - propagacion - excepciones unchecked java
CheckException solo acepta métodos de 0 parámetros; ¿Cómo pruebo que otros métodos arrojen excepciones? (5)
Como se señaló, este es un gran lugar para métodos anónimos.
Así es como lo hago. "Pedí prestado" esto a 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;
Luego llámalo con algo como:
CheckException(ETestingException,
procedure begin FMyClass.RaiseTestingException end,
''The ETestingException exception didn''''t get raised. That is impossible!'');
Me pregunto cuál es la mejor práctica para probar excepciones en dunit. No estoy muy familiarizado con los punteros de método en Delphi. ¿Hay alguna posibilidad de vincular argumentos a un puntero de método para que pueda invocarse sin argumentos? Por el momento siempre escribo un método adicional que hace esto ''vinculante'' manualmente. Esto será molesto si el SUT tiene muchos métodos de lanzamiento.
// 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;
Esta es la versión mejorada y funcional de la respuesta de Nick Hodges, que subclases TestFramework.TTestCase
de 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://.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;
Una buena ventaja de este método para comprobar si se generó una excepción en Start/StopExpectingException()
es que puede ejecutar el testrunner en la compilación de depuración y no lo molestará con "Exceptived was raised. Break? Continue?" cada vez que se produce una excepción, aunque se haya manejado.
No sé si DUnit lo admite aún, pero este es un caso de uso perfecto para los métodos anónimos que se introdujeron en Delphi 2010. Si DUnit no es compatible, puede modificar fácilmente la fuente usted mismo.
Puede usar StartExpectingException
para rodear su llamada a su método).
StartExpectingException(MyException);
MyMethod(MyParam);
StopExpectingException();
Usar StartExpectingException()
no es la mejor manera en caso de que desee probar más de un caso de excepción. Para probar todos los casos posibles en mi procedimiento de prueba, junto con las excepciones uso este 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;
La razón por la que uso ShowMessage(''Error! There should be exception: Exxx here!'');
en lugar del Check(false, ''There should have been an EListError.'');
proporcionado Check(false, ''There should have been an EListError.'');
El método es que en mi caso (Delphi6) el Check(boolean, ''Message'')
no funciona: no muestra el mensaje en caso de que Check esté adentro, try...except
bloquear (no sé por qué).