Управляемое данными тестирование DUnit - PullRequest
11 голосов
/ 01 апреля 2009

Обычно DUnit работает, когда вы пишете некоторые опубликованные методы, а DUnit запускает их как тесты. То, что я хочу сделать, немного по-другому. Я хочу создавать тесты во время выполнения на основе данных. Я пытаюсь протестировать определенный модуль, который обрабатывает входные файлы для создания выходных файлов. У меня есть набор тестовых входных файлов с соответствующими известными хорошими выходными файлами. Идея состоит в том, чтобы динамически создавать тесты, по одному для каждого входного файла, которые обрабатывают входные данные и сравнивают выходные данные с известными хорошими.

Фактический источник данных здесь не важен. Трудность состоит в том, чтобы заставить DUnit вести себя управляемым данными способом. Ради этой проблемы предположим, что источником данных был просто генератор случайных чисел. Вот пример конкретной проблемы, которая доходит до сути проблемы:

Создайте несколько тестовых объектов (TTestCase или что-то еще) во время выполнения, скажем, 10 из них, где каждый

  1. Именуется во время выполнения из случайно сгенерированного целого числа. (Под «именем» я подразумеваю название теста, которое отображается в дереве тестового прогона.)
  2. Проходит или не срабатывает на основе случайного целого числа. Проход по четным, провал по нечетным.

С точки зрения дизайна DUnit, он выглядит так, как будто он был разработан с достаточной гибкостью, чтобы сделать такие вещи возможными. Я не уверен, что это так. Я пытался создать свой собственный тестовый класс, унаследованный от TAbstractTest и ITest, но некоторые важные методы не были доступны. Я также пытался наследовать от TTestCase, но этот класс тесно связан с идеей запуска опубликованных методов (а тесты названы в честь методов, поэтому я не мог просто написать один, скажем, 'go', потому что все мои тесты будут называться «go», и я хочу, чтобы все мои тесты назывались индивидуально).

Или, альтернативно, есть ли альтернатива DUnit, которая могла бы делать то, что я хочу?

Ответы [ 2 ]

18 голосов
/ 01 апреля 2009
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.
2 голосов
/ 01 апреля 2009

Я бы сказал, что вы в основном хотите иметь одну функцию «супер-теста», которая затем вызывает другие тесты, по одному для каждого файла данных. Это то, что мы делаем с одним из наших тестов DUnit. Вы просто загружаете каждый доступный файл по очереди в цикле и запускаете тест с проверками по мере необходимости.

Альтернатива, которую мы также используем в том же проекте для тестирования конечного приложения, его загрузки и анализа данных, состоит в том, чтобы использовать что-то вроде FinalBuilder для зацикливания приложения (возможно, вы могли бы зациклить и приложение DUnit и использовать параметр) с различными файлами данных. Затем приложение запускается, выполняет анализ, а затем завершает работу после сохранения. Затем другое приложение сравнивает полученные данные с идеальными данными и при необходимости сообщает об ошибке.

...