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

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

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

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

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

或者,是否有 DUnit 的替代方案可以实现我想要的功能?

有帮助吗?

解决方案

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.

其他提示

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top