Подтвердить что ты не робот

Могу ли я передать набор в тестовый пример в DUnitX?

Я пытаюсь проверить состояние объекта после запуска теста. Это состояние содержится в множестве. Возможно ли передать ожидаемое состояние в тестовый пример с использованием атрибутов DUnitX, чтобы я мог использовать один и тот же тест для всех разных входов?

Я пытался передать набор как константу или как набор, но в моей тестовой процедуре он всегда приходит как пустой набор.

  • Возможно ли вообще использовать атрибуты?
  • Как бы вы могли проверить, идентичны ли наборы?

Пример кода:

type
  TResult = (resOK,resWarn,resError);
  TResultSet = set of TResult;

const
  cErrWarn : TResultSet = [resWarn];

type
  [TestFixture]
  TMyTest = class(TBaseTest)
    [Test]
    [TestCase('Demo1','InputA,[resWarn]')] // <-- tried as a set
    [TestCase('Demo2','InputB,cErrWarn')]  // <-- tried as a constant

    procedure Test(Input:string; ExpectedResult: TResultSet);
  end;

procedure TMyTest.Test(Input:string; ExpectedResult: TResultSet);
begin
  // ExpectedResult is always the empty set []
  RunTests(MyObject(Input));
  Assert.AreEqual(ExpectedResult, MyObject.ResultSet);
end;

Я также попытался определить ожидаемый результат как массив, но затем DUnitX больше не вызывает тест. Наверное, это просто "слишком много"

    procedure Test(Input:string; ExpectedResult: array of TResult);

Лучшее, что я мог придумать до сих пор, это использовать следующий подход. Возьмите образец до трех (вставьте свое любимое целое число здесь...) ожидаемые состояния и проверьте их отдельно. На самом деле это не то, на что я надеялся, но это трюк.

    procedure Test(Input:string; R1,R2,R3: TResult);

Помощь приветствуется.:)

4b9b3361

Ответ 1

Вы используете TestCaseAttribute, чтобы указать аргументы, которые должны быть переданы вашему тестовому методу. Однако он просто не предлагает поддержки для передачи наборов в качестве аргументов. Вы можете видеть, что это так, посмотрев на константу Conversions, объявленную в блоке DUnitX.Utils. Он преобразует любое преобразование в набор в ConvFail.

Итак, если вы хотите указать эти данные с помощью атрибутов, вам понадобится расширить рамки тестирования. Вы можете получить собственный потомок от CustomTestCaseSourceAttribute и переопределить GetCaseInfoArray, чтобы декодировать ваши аргументы. В качестве грубого примера вы можете использовать это:

type
  MyTestCaseAttribute = class(CustomTestCaseSourceAttribute)
  private
    FCaseInfo: TestCaseInfoArray;
  protected
    function GetCaseInfoArray: TestCaseInfoArray; override;
  public
    constructor Create(const ACaseName: string; const AInput: string; const AExpectedResult: TResultSet);
  end;

constructor MyTestCaseAttribute.Create(const ACaseName, AInput: string; const AExpectedResult: TResultSet);
begin
  inherited Create;
  SetLength(FCaseInfo, 1);
  FCaseInfo[0].Name := ACaseName;
  SetLength(FCaseInfo[0].Values, 2);
  FCaseInfo[0].Values[0] := TValue.From<string>(AInput);
  FCaseInfo[0].Values[1] := TValue.From<TResultSet>(AExpectedResult);
end;

function MyTestCaseAttribute.GetCaseInfoArray: TestCaseInfoArray;
begin
  Result := FCaseInfo;
end;

Затем вы можете добавить следующий атрибут к вашему методу тестирования:

[MyTestCase('Demo2', 'InputB', [resWarn])]
procedure Test(Input: string; ExpectedResult: TResultSet);

Я избегал использования RTTI здесь для простоты, но использование RTTI даст вам большую гибкость. Вы передадите аргумент как строку и декодируете его с помощью RTTI, как это делает код в DUnitX. Это означает, что вам не нужно писать индивидуальные атрибуты каждый раз, когда вы хотите использовать заданный аргумент.

Еще лучше было бы реализовать это в DUnitX, расширив карту Conversions до наборов накладок и представив это как патч. Я уверен, что другие сочтут это полезным.

Ответ 2

Добавьте эту функцию преобразования в DUnitX.Utils и поместите ее в матрицу преобразований для tkUString в tkSet (из-за ограничений StringToSet и TValue это работает только для наборов до 32 элементов, для более крупных наборов до 256 элементов требуется еще больше кода):

function ConvStr2Set(const ASource: TValue; ATarget: PTypeInfo; out AResult: TValue): Boolean;
begin
  TValue.Make(StringToSet(ATarget, ASource.AsString), ATarget, AResult);
  Result := True;
end;

Также вам нужно использовать другой разделитель char для параметров или он не будет разбивать их неправильно:

[TestCase('Demo1','InputA;[resWarn,resError]', ';')]