CheckException sólo acepta métodos 0 de parámetros; ¿Cómo se prueba que los otros métodos que generan excepciones?

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

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;
¿Fue útil?

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ó

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top