11

DUnit 通常的工作方式是编写一些已发布的方法,然后 DUnit 将它们作为测试运行。我想做的有点不同。我想在运行时根据数据创建测试。我正在尝试测试一个处理输入文件以创建输出文件的特定模块。我有一组带有相应已知良好输出文件的测试输入文件。这个想法是动态创建测试,每个输入文件一个,处理输入并根据已知的好文件检查输出。

然而,这里的实际数据来源并不重要。困难在于使 DUnit 以数据驱动的方式运行。为了这个问题,假设数据源只是一个随机数生成器。这是一个触及困难核心的具体问题示例:

在运行时创建一些测试对象(TTestCase 或其他),比如 10 个,其中每个

  1. 在运行时从随机生成的整数中命名。(“名称”是指出现在测试运行器树中的测试名称。)
  2. 通过或失败基于随机整数。偶数通过,奇数失败。

从 DUnit 的设计来看,它的设计似乎考虑到了足够的灵活性以使这些事情成为可能。我不确定是不是这样。我尝试通过从 TAbstractTest 和 ITest 继承来创建自己的测试类,但无法访问一些关键方法。我也尝试从 TTestCase 继承,但该类与运行已发布方法的想法密切相关(并且测试以方法命名,所以我不能只使用一个名为“go”的类,因为那时我所有的测试都将被称为“go”,我希望我的所有测试都单独命名)。

或者,是否有一些替代 DUnit 可以做我想做的事情?

4

2 回答 2

18
program UnitTest1;

{$IFDEF CONSOLE_TESTRUNNER}
{$APPTYPE CONSOLE}
{$ENDIF}

uses
  Forms, Classes, SysUtils,
  TestFramework,
  GUITestRunner,
  TextTestRunner;

{$R *.RES}

type
  TIntTestCase = class(TTestCase)
  private
    FValue: Integer;
  public
    constructor Create(AValue: Integer); reintroduce;
    function GetName: string; override;
  published
    procedure Run;
  end;

{ TIntTestCase }

constructor TIntTestCase.Create(AValue: Integer);
begin
  inherited Create('Run');
  FValue := AValue;
end;

function TIntTestCase.GetName: string;
begin
  Result := Format('Run_%.3d', [FValue]);
end;

procedure TIntTestCase.Run;
begin
  Check(FValue mod 2 = 0, Format('%d is not an even value', [FValue]));
end;

procedure RegisterTests;
const
  TestCount = 10;
  ValueHigh = 1000;
var
  I: Integer;
begin
  Randomize;
  for I := 0 to TestCount - 1 do
    RegisterTest(TIntTestCase.Create(Random(ValueHigh) + 1));
end;

begin
  Application.Initialize;
  RegisterTests;
  if IsConsole then
    TextTestRunner.RunRegisteredTests
  else
    GUITestRunner.RunRegisteredTests;
end.
于 2009-04-01T11:58:03.463 回答
2

我想说你基本上想要一个“超级测试”函数,然后调用其他测试,每个数据文件一个。这就是我们对 DUnit 测试之一所做的事情。您只需循环加载每个可用文件,并根据需要使用 Check 运行测试。

另一种方法,我们也在同一个项目中用于测试最终应用程序及其数据加载和分析,是使用类似 FinalBuilder 的东西来循环应用程序(假设你也可以循环 DUnit 应用程序并使用参数)各种不同的数据文件。然后应用程序运行,进行分析,然后在保存后退出。然后另一个应用程序将结果数据与理想数据进行比较,并在适当时报告失败。

于 2009-04-01T11:47:53.253 回答