verificadas propagacion excepciones chequeadas delphi unit-testing exception dunit

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é).