CheckException sólo acepta métodos 0 de parámetros; ¿Cómo se prueba que los otros métodos que generan excepciones?
-
26-09-2019 - |
Pregunta
Me pregunto cuál es la mejor práctica para la prueba de excepciones en DUnit. No estoy muy familiarizado con los punteros método de Delphi. ¿Hay alguna posibilidad de argumentos se unen a un puntero método para que pudiera ser invocado sin argumentos. Por el momento Siempre escribo un método adicional que hace esto 'vinculante' manualmente. Esto va a ser molesto si el SUT tiene una gran cantidad de métodos de tirar.
// 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;
Solución
Puede utilizar StartExpectingException
para rodear el método de la llamada).
StartExpectingException(MyException);
MyMethod(MyParam);
StopExpectingException();
Otros consejos
No sé si DUnit apoya todavía, pero este es un caso de uso perfecto para los métodos anónimos que fueron introducidos en Delphi 2010. Si DUnit no lo soporta, entonces puede modificar fácilmente la fuente sí mismo.
Como se ha señalado, este es un gran lugar para los métodos anónimos.
Así es como lo hago. I "prestada" de Alex este 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;
A continuación, llamar con algo como:
CheckException(ETestingException,
procedure begin FMyClass.RaiseTestingException end,
'The ETestingException exception didn''t get raised. That is impossible!');
Para uso StartExpectingException()
no es la mejor manera en caso de que quiera prueba de más de uno de los casos de excepción. Con el fin de probar todos los casos posibles en mi procedimiento de prueba, junto con excepciones utilizo 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 utilizo ShowMessage('Error! There should be exception: Exxx here!');
en lugar del método Check(false, 'There should have been an EListError.');
proporcionado es que en mi caso (Delphi6) la Check(boolean, 'Message')
no funciona - no muestra el mensaje en caso de que Check es el bloque try...except
interior (no sé por qué).
Este es el trabajo y mejorada versión de respuesta Nick Hodges, que subclases de 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 buen bono a este método para comprobar si una excepción fue levantado sobre Start/StopExpectingException()
es que puede ejecutar el TestRunner en la versión de depuración y no va a mantener a molestarlo "se elevó Excepción. Break? ¿Continuar?" cada vez que se lanza una excepción -. a pesar de que se manejó