CheckException只接受0参数方法;我如何测试其他方法抛出异常?

时间:2011-01-06 08:46:25

标签: delphi unit-testing exception dunit

我想知道在dunit中测试异常的最佳做法是什么。我对Delphi中的方法指针不是很熟悉。是否有可能将参数绑定到方法指针,以便可以在没有参数的情况下调用它。目前我总是写一个额外的方法来手动执行“绑定”。如果SUT有很多投掷方法,那将会很烦人。

// 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;

5 个答案:

答案 0 :(得分:43)

您可以使用StartExpectingException包围您的方法调用。)

StartExpectingException(MyException);
MyMethod(MyParam);
StopExpectingException();

答案 1 :(得分:3)

我不知道DUnit是否支持它,但这是Delphi 2010中引入的匿名方法的完美用例。如果DUnit不支持它,那么您可以自己轻松修改源代码。

答案 2 :(得分:3)

如上所述,这是匿名方法的好地方。

我是这样做的。我从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;

然后用以下内容调用它:

CheckException(ETestingException, 
             procedure begin FMyClass.RaiseTestingException end,      
             'The ETestingException exception didn''t get raised.  That is impossible!');

答案 3 :(得分:1)

如果您想测试多个异常案例,使用StartExpectingException()并不是最好的方法。为了在我的测试程序中测试所有可能的情况,除了例外我使用这个算法:

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;

我使用ShowMessage('Error! There should be exception: Exxx here!'); 而不是提供的Check(false, 'There should have been an EListError.');方法的原因是,在我的情况下(Delphi6),Check(boolean, 'Message')不起作用 - 它不显示消息,以防检查在try...except块内(不知道原因)。

答案 4 :(得分:0)

这是Nick Hodges的答案的工作和改进版本,其中的子类是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;

这种检查是否在Start/StopExpectingException()上引发异常的方法的一个很好的好处是,您可以在调试版本中运行testrunner并且它不会一直困扰您“异常被提出。中断?继续?”每次引发异常时 - 即使它已被处理。