Einzelnen Beitrag anzeigen

Benutzerbild von Lloyd Bates
Lloyd Bates

Registriert seit: 4. Jun 2009
3 Beiträge
 
Delphi XE Professional
 
#6

AW: Dsharp unit testing , AV nicht verstanden

  Alt 14. Apr 2015, 08:00
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.
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.
In theory, there ought to be no difference between theory and practice. In practice, there is.

Geändert von Lloyd Bates (14. Apr 2015 um 08:05 Uhr)
  Mit Zitat antworten Zitat