Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Softwaretests und Qualitätssicherung (https://www.delphipraxis.net/86-softwaretests-und-qualitaetssicherung/)
-   -   Dsharp unit testing , AV nicht verstanden (https://www.delphipraxis.net/184675-dsharp-unit-testing-av-nicht-verstanden.html)

bernhard_LA 13. Apr 2015 21:58

Dsharp unit testing , AV nicht verstanden
 
ich möchte unit testing mit Unterstützung des D# Frameworks durchführen. mein erstes sample sieht wie folgt aus


Delphi-Quellcode:


unit Unit_TCustomtestCase;

interface

uses
  TestFramework, Types, Generics.Collections, Classes, SysUtils,
  DSharp.Testing.DUnit;

type
  TCustomParams = class
    StartFolder: String;
    StartValue: Integer;
    StartParam: Real;
  end;

type

  TCustomtestCase = class(TTestCase)

  private
    FtestParam: TCustomParams;

  protected
    procedure SetUp; override;
    procedure TearDown; override;

  published
    [TestCase('''c:\temp'',1 ,3.1415')]
    [TestCase('''d:\temp'',1 ,3.1415')]
    [TestCase('''e:\temp'',1 ,3.1415')]
    [TestCase('''f:\temp'',1 ,3.1415')]
    procedure InittestParams(StartFolder: String; StartValue: Integer;
      StartParam: Real);

  end;

implementation

{ TCustomtestCase }

procedure TCustomtestCase.InittestParams(StartFolder: String;
  StartValue: Integer; StartParam: Real);
begin
  FtestParam.StartFolder := StartFolder;
  FtestParam.StartValue := StartValue;
  FtestParam.StartParam := StartParam;

  checkEquals(FtestParam.StartParam, StartValue);
end;

procedure TCustomtestCase.SetUp;
begin
  inherited;
  FtestParam := TCustomParams.Create;
end;

procedure TCustomtestCase.TearDown;
begin
  inherited;
  FtestParam.Free;
end;

initialization

RegisterTest(TCustomtestCase.Suite);

end.

Wenn ich das Schlüsselwort
Zitat:

// published
auskommentiere kann ich zwar kompilieren erhalte aber nur einen Testcase, die Anderen Attribute werden nicht berücksichtigt.

Verwende ich
Zitat:

published
bekomme ich eine AV mit dem Hinweis auf DSharp.Core.Reflection.pas ???

Was mache ich denn falsch?

Jens01 13. Apr 2015 22:38

AW: Dsharp unit testing , AV nicht verstanden
 
Wäre es nicht sinnvoller, gleich mit DUnitX zu testen.

Sir Rufo 13. Apr 2015 23:17

AW: Dsharp unit testing , AV nicht verstanden
 
Funktioniert denn das Beispiel?

https://bitbucket.org/sglienke/dshar...ing/?at=master

Stevie 14. Apr 2015 07:08

AW: Dsharp unit testing , AV nicht verstanden
 
Zitat:

Zitat von Jens01 (Beitrag 1297583)
Wäre es nicht sinnvoller, gleich mit DUnitX zu testen.

Nein, wäre es nicht. Die DSharp Extensions für DUnit funktionieren hervorragend (und die gibt's schon länger als DUnitX).

Zitat:

Zitat von bernhard_LA (Beitrag 1297581)
Verwende ich
Zitat:

published
bekomme ich eine AV mit dem Hinweis auf DSharp.Core.Reflection.pas ???

Was mache ich denn falsch?

Ich hab deinen Test gerade erfolgreich ausgeführt. 4 grüne Tests mit den entsprechenden Parametern.
Getestet habe ich sowohl mit den Ständen aus master und feature/spring4d-compatibility und auf XE und XE5.

Welche Version von DSharp benutzt du auf welcher Delphi Version? Und wo genau kommt die AV?

Nachtrag:
Ich bekomm zwar keine AV aber ich seh, wo das Problem ist (und die Tests sollten ja eigentlich rot sein ^^).
Erstens müssen die Argumente durch ein Semikolon getrennt werden und der String muss nicht doppelt gequotet werden.
Dann gibt es derzeit noch die kleine Niggeligkeit, dass das Float umwandeln von den locale Settings auf deinem System abhängig ist.

Ich musste für korrekte Werte das also so schreiben:
Delphi-Quellcode:
[TestCase('c:\temp;1;3,1415')]
[TestCase('d:\temp;1;3,1415')]
[TestCase('e:\temp;1;3,1415')]
[TestCase('f:\temp;1;3,1415')]
Für einen Punkt als Dezimaltrenner muss DSharp.Core.Reflection.ConvStr2Float entsprechend angepasst werden.

Du kannst dir aber auch eine eigene Attribut Klasse für deinen Test bauen (leider unterstützt Delphi keine open arrays in Attributen, daher der zugegebenermaßen hässliche Workaround mit nem String - den macht DUnitX übrigens auch nicht anders), die sähe dann so aus:

Delphi-Quellcode:
type
  CustomParamsTestCaseAttribute = class(TestCaseAttribute)
  public
    constructor Create(StartFolder: String; StartValue: Integer; StartParam: Real);
  end;

constructor CustomParamsTestCaseAttribute.Create(StartFolder: String;
  StartValue: Integer; StartParam: Real);
begin
  SetLength(FValues, 3);
  FValues[0] := StartFolder;
  FValues[1] := StartValue;
  FValues[2] := StartParam;
end;
Dann kannst du über deinen Test schreiben:
Delphi-Quellcode:
[CustomParamsTestCase('c:\temp', 1, 3.1415)]
[CustomParamsTestCase('d:\temp', 1, 3.1415)]
[CustomParamsTestCase('e:\temp', 1, 3.1415)]
[CustomParamsTestCase('f:\temp', 1, 3.1415)]

Sir Rufo 14. Apr 2015 07:58

AW: Dsharp unit testing , AV nicht verstanden
 
@Stevie

Da wollte ich gerade diese Beschränkungen zur Sprache bringen, da nimmst du mir doch alles aus dem Mund :D

Trotz dieser Niggeligkeiten ein cooles Feature :thumb:

Lloyd Bates 14. Apr 2015 08:00

AW: Dsharp unit testing , AV nicht verstanden
 
Ich nutze für die DSharp TestCase Attribute einen kleinen generator den ich irgendwann mal des nächtens geschrieben habe.
Bitte nicht über die Codequalität streiten, er leistet mir gute Dienste. :wink:
Benötigt wird außerdem Spring4D weil ich dessen IList verwende.

Zur Benutzung:
Variable von TTestAttributeGenerator erzeugen, "Name" ist der Name für das generierte Attribut und die IList<TPair<string,string>> sind die Argumente für das Attribut.
TPair<string,string> ist dabei Name und Typ als String.

Beispiel:
Delphi-Quellcode:
procedure Test;
var
  args: IList<TPair<string,string>>;
  generator: TTestAttributeGenerator;
begin
  args := TCollections.CreateList<TPair<string,string>>;
  args.Add(TPair<string,string>.Create('StartFolder', 'string'));
  args.Add(TPair<string,string>.Create('StartValue', 'Integer'));
  args.Add(TPair<string,string>.Create('StartParam', 'Real'));

  generator := TTestAttributeGenerator.Create('CustomParamsTestCase', args);

  Clipboard.AsText := 'type' + sLineBreak + generator.GetIntf() + sLineBreak + sLineBreak + generator.GetImpl();
end;
Und das generiert dann diesen Code:
Delphi-Quellcode:
type
  CustomParamsTestCaseAttribute = class(TestCaseAttribute)
  public
    constructor Create(StartFolder: string; StartValue: Integer; StartParam: Real);
  end;

{ CustomParamsTestCaseAttribute }

constructor CustomParamsTestCaseAttribute.Create(StartFolder: string; StartValue: Integer; StartParam: Real);
begin
  SetLength(FValues, 3);
  FValues[0] := TValue.From<string>(StartFolder);
  FValues[1] := TValue.From<Integer>(StartValue);
  FValues[2] := TValue.From<Real>(StartParam);
end;
Und hier der Source Code:
Delphi-Quellcode:
unit uTestAttributeGenerator;

interface

uses
  SysUtils,
  Generics.Collections,
  Spring.Collections;

type
  TTestAttributeGenerator = record
  private
    fName: string;
    fArgs: IList<TPair<string,string>>;
    fIntf: string;
    fImpl: string;

    procedure EnsureGenerated;
  public
    constructor Create(const Name: string; const Args: IList<TPair<string,string>>);
   
    function GetIntf: string;
    function GetImpl: string;
  end;

implementation

uses
  StrUtils;

const
  AttributeName = '$(Name)';
  AttributeArg = '$(Arg)';

  ArgCount = '$(ArgCount)';
  ArgIndex = '$(ArgIndex)';
  ArgName = '$(ArgName)';
  ArgType = '$(ArgType)';
  ArgAssign = '$(ArgAssign)';
 
  ResolvedAttributeArg = ArgName + ': ' + ArgType;
  ResolvedAttributeArgMultiple = ResolvedAttributeArg + '; ' + AttributeArg;
  ResolvedArgAssign = 'FValues[' + ArgIndex + '] := TValue.From<' + ArgType + '>(' + ArgName + ');';
  ResolvedArgAssignMutli = ResolvedArgAssign + sLineBreak + ' ' + ArgAssign;
 
  AttributeTemplateIntf =
    ' ' + AttributeName + 'Attribute = class(TestCaseAttribute)' + sLineBreak +
    ' public' + sLineBreak +
    '   constructor Create(' + AttributeArg + ');' + sLineBreak +
    ' end;';
   
  AttributeTemplateImpl =
    '{ ' + AttributeName + 'Attribute }' + sLineBreak +
    '' + sLineBreak +
    'constructor ' + AttributeName + 'Attribute.Create(' + AttributeArg + ');' + sLineBreak +
    'begin' + sLineBreak +
    ' SetLength(FValues, ' + ArgCount + ');' + sLineBreak +
    ' ' + ArgAssign + sLineBreak +
    'end;';
 
{ TTestAttributeGenerator }

constructor TTestAttributeGenerator.Create(const Name: string; const Args: IList<TPair<string,string>>);
begin
  if Name = '' then
    raise EArgumentException.Create('Argument [Name] can''t be empty');
  if not Assigned(Args) then
    raise EArgumentNilException.Create('Argument [Args] has to be assigned');
  if Args.Count = 0 then
    raise EArgumentException.Create('Argument [Args] can''t be empty');
   
  fName := Name;
  fArgs := Args;
  fIntf := AttributeTemplateIntf;
  fImpl := AttributeTemplateImpl;
end;

function TTestAttributeGenerator.GetIntf: string;
begin
  EnsureGenerated();
 
  Result := fIntf;
end;

function TTestAttributeGenerator.GetImpl: string;
begin
  EnsureGenerated();
 
  Result := fImpl;
end;

procedure TTestAttributeGenerator.EnsureGenerated;
var
  i: Integer;
  s: string;
begin
  if not Assigned(fArgs) then
    Exit;
 
  // replace AttributeName
  fIntf := StringReplace(fIntf, AttributeName, fName, [rfReplaceAll]);
  fImpl := StringReplace(fImpl, AttributeName, fName, [rfReplaceAll]);
 
  // replace Argument count
  fIntf := StringReplace(fIntf, ArgCount, IntToStr(fArgs.Count), [rfReplaceAll]);
  fImpl := StringReplace(fImpl, ArgCount, IntToStr(fArgs.Count), [rfReplaceAll]);

  for i := 0 to Pred(fArgs.Count) do
  begin
    // replace Arg
    s := IfThen(i = Pred(fArgs.Count), ResolvedAttributeArg, ResolvedAttributeArgMultiple);
    fIntf := StringReplace(fIntf, AttributeArg, s, [rfReplaceAll]);
    fImpl := StringReplace(fImpl, AttributeArg, s, [rfReplaceAll]);
   
    // replace Assign
    s := IfThen(i = Pred(fArgs.Count), ResolvedArgAssign, ResolvedArgAssignMutli);
    fIntf := StringReplace(fIntf, ArgAssign, s, [rfReplaceAll]);
    fImpl := StringReplace(fImpl, ArgAssign, s, [rfReplaceAll]);

    // replace Argument Name
    fIntf := StringReplace(fIntf, ArgName, fArgs[i].Key, [rfReplaceAll]);
    fImpl := StringReplace(fImpl, ArgName, fArgs[i].Key, [rfReplaceAll]);
   
    // replace Argument Type
    fIntf := StringReplace(fIntf, ArgType, fArgs[i].Value, [rfReplaceAll]);
    fImpl := StringReplace(fImpl, ArgType, fArgs[i].Value, [rfReplaceAll]);

    // replace Argument Index
    fIntf := StringReplace(fIntf, ArgIndex, IntToStr(i), [rfReplaceAll]);
    fImpl := StringReplace(fImpl, ArgIndex, IntToStr(i), [rfReplaceAll]);
  end;
   
  fArgs := nil;
end;

end.

bernhard_LA 14. Apr 2015 12:10

AW: Dsharp unit testing , AV nicht verstanden
 
Liste der Anhänge anzeigen (Anzahl: 1)
Danke für die schnelle Hilfe , ich habe mich für den einfachsten Weg entschieden

Wir haben im Team alles WIn 7 mit Lang=german Punkt oder Komma sollte kein Thema für uns werden.


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:11 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz