我可以将一个集合传递给DUnitX中的测试用例吗?

时间:2016-01-26 08:50:05

标签: unit-testing delphi 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甚至不再调用测试。可能只是&#34;太多&#34;

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

到目前为止,我能想出的最好的方法是使用以下方法。获取最多三个样本(在此处插入您喜欢的整数...)预期状态并单独检查这些状态。这不是我所希望的,但它确实可以解决问题。

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

非常感谢帮助。 :)

2 个答案:

答案 0 :(得分:12)

您正在使用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中的代码一样。这意味着每次要使用set参数时都不需要编写定制属性。

更好的方法是在DUnitX中通过将Conversions地图扩展到封面集来实现它,并将其作为补丁提交。我相信其他人会发现它很有用。

答案 1 :(得分:11)

将此转换功能添加到DUnitX.Utils并将其放入tkUStringtkSet的转化矩阵中(由于StringToSetTValue的限制适用于最多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]', ';')]