Estoy tratando de verificar el estado de un objeto después de ejecutar una prueba. Este estado está contenido en un conjunto. ¿Es posible pasar el estado esperado al caso de prueba usando Atributos DUnitX, de modo que pueda usar la misma prueba para todas las diferentes entradas?

Intenté pasar el conjunto como una constante o como un conjunto, pero en mi rutina de Prueba siempre llega como un conjunto vacío.

  • ¿Es esto posible usar atributos?
  • ¿Cómo probarías si los conjuntos son idénticos?

Código de ejemplo:

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;

También intenté definir el resultado esperado como una matriz, pero luego DUnitX ya ni siquiera llama a la prueba. Probablemente sea "demasiado"

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

Lo mejor que se me ocurrió hasta ahora fue utilizar el siguiente enfoque. Tome una muestra de hasta tres (inserte su entero favorito aquí ...) estados esperados y verifíquelos por separado. Esto no es realmente lo que esperaba, pero funciona.

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

Se agradece enormemente la ayuda. :)

18
Lübbe Onken 26 ene. 2016 a las 11:50

2 respuestas

La mejor respuesta

Estás usando TestCaseAttribute para especificar los argumentos que se pasarán a tu método de prueba. Sin embargo, simplemente no ofrece ningún soporte para pasar conjuntos como argumentos. Puede ver que esto es así al observar la constante Conversions declarada en la unidad DUnitX.Utils. Asigna cualquier conversión a un conjunto a ConvFail.

Por lo tanto, si desea especificar estos datos utilizando atributos, necesitará ampliar el marco de prueba. Puede derivar su propio descendiente de CustomTestCaseSourceAttribute y anular GetCaseInfoArray para decodificar sus argumentos establecidos. Como ejemplo burdo, podría usar esto:

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;

Luego puede agregar el siguiente atributo a su método de prueba:

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

He evitado usar RTTI aquí por simplicidad, pero usar RTTI le daría más flexibilidad. Pasaría el argumento como una cadena y lo decodificaría usando RTTI, tal como lo hace el código en DUnitX. Esto significa que no necesita escribir atributos personalizados cada vez que desee utilizar un argumento establecido.

Aún mejor sería implementar esto dentro de DUnitX extendiendo el mapa Conversions para cubrir conjuntos y enviarlo como un parche. Estoy seguro de que a otros les resultará útil.

14
David Heffernan 26 ene. 2016 a las 09:33

Agregue esta función de conversión a DUnitX.Utils y colóquela en la matriz de conversiones para tkUString a tkSet (debido a las limitaciones de StringToSet y TValue, esto solo funciona para conjuntos hasta 32 elementos, para conjuntos más grandes de hasta 256 elementos se requiere más código):

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

También debe usar un carácter separador diferente para los parámetros o los dividirá mal:

[TestCase('Demo1','InputA;[resWarn,resError]', ';')]
13
Stefan Glienke 26 ene. 2016 a las 12:55