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

发布于 2024-10-10 18:31:56 字数 872 浏览 8 评论 0原文

我想知道测试 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;

I'm wondering what's the best practice to test for exceptions in dunit. I am not very familiar with method pointers in Delphi. Is there any possibility to bind arguments to a method pointer so that it could be invoked without arguments. At the moment I always write an additional method which does this 'binding' manually. This is going to be annoying if the SUT has a lot of throwing methods.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

不再见 2024-10-17 18:31:56

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

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

You can use StartExpectingException to surround your your method call).

StartExpectingException(MyException);
MyMethod(MyParam);
StopExpectingException();
谢绝鈎搭 2024-10-17 18:31:56

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

I don't know if DUnit supports it yet, but this is a perfect use case for anonymous methods which were introduced in Delphi 2010. If DUnit doesn't support it then you can easily modify the source yourself.

梦亿 2024-10-17 18:31:56

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

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

As noted, this is a great place for anonymous methods.

Here's how I do it. I "borrowed" this from 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;

Then call it with something like:

CheckException(ETestingException, 
             procedure begin FMyClass.RaiseTestingException end,      
             'The ETestingException exception didn''t get raised.  That is impossible!');
本宫微胖 2024-10-17 18:31:56

如果您想测试多个异常情况,那么使用 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 an EListError.'); 方法,在我的例子中(Delphi6)是 Check(boolean, 'Message' ) 不起作用 - 如果 Check 位于 try... except 块内,它不会显示消息(不知道为什么)。

To use StartExpectingException() is not the best way in case you want to test more then one Exception cases. In order to test all possible cases in my Test procedure, together with exceptions I use this algorithm:

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;

The reason why I use ShowMessage('Error! There should be exception: Exxx here!');
instead of the provided Check(false, 'There should have been an EListError.'); method is that in my case (Delphi6) the Check(boolean, 'Message') does not work - it does not show the message in case that Check is inside try...except block (do not know why).

这是 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( 是否引发异常的方法) 的一个很好的好处) 的优点是您可以在调试版本中运行测试运行程序,并且它不会一直以“引发异常。中断?继续?”的方式困扰您。每次引发异常时——即使它已被处理。

This is the working and improved version of Nick Hodges' answer, which sub-classes DUnit's 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;

A nice bonus to this method of checking if an exception was raised over Start/StopExpectingException() is that you can run the testrunner in the debug build and it won't keep bothering you with "Exception was raised. Break? Continue?" every time an exception is raised--even though it was handled.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文