Pull to refresh

По мотивам GUIRunner

Reading time 3 min
Views 4.9K
Часть 1.
Часть 2.
Часть 3.

Сегодня дописал пост о том, как мы решили написать свой GUIRunner для FireMonkey. В комментарии к посту в одной из соцсетей Алексей Тимохин обратил мое внимание на другой известный фреймворк для тестирования — DUnitX.
Я пытался найти альтернативу, использовать консольный вариант, но Александр был неумолим. Когда же зайдя в репозиторий я увидел готовый GUIRunner под FireMonkey, совсем поник.

Однако.

После первого запуска первым моим сообщением Александру было — " lol. Там «галочек» нету." Так что проблему решал не зря. После более внимательного изучения сложилось впечатление, что человек, который писал эту форму, тоже отчасти «поглядывал» в Original GUIRunner.

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

Ряд ошибок мы допустили практически одинаковых. В посте я писал о том, как мы «связываем» тесты и ветки и в конце закончил предложением о рефакторинге с использованием TDictionary. Напомню, как в оригинале:

  l_Test.GUIObject := aNode.Items[l_Index];
  ...
  l_TreeViewItem.Tag := FTests.Add(aTest);

Разработчик DUnitX поступил примерно также, правда, он сделали обертку над TTreeViewItem (в будущем добавлю к себе):

type
  TTestNode = class(TTreeViewItem)
  strict private
    FFullName: String;
    FImage: TImage;
  public
    constructor Create(Owner: TComponent; Text: String; TestFullName: String); reintroduce;
    destructor Destroy; override;
    property FullName: String read FFullName;
    procedure SetResultType(resultType: TTestResultType);
    procedure Reload;
  end;

И связал каждый тест с веткой по имени теста.

function TGUIXTestRunner.GetNode(FullName: String): TTreeViewItem;
var
  i: Integer;
begin
  Result := nil;
  i := 0;
  repeat begin
    if (TestTree.ItemByGlobalIndex(i) as TTestNode).FullName = FullName then
      Result := TestTree.ItemByGlobalIndex(i);
    Inc(i);
   end
   until Assigned(Result) or (i >= TestTree.GlobalCount);
end;

Удивило меня другое:

  FFailedTests: TDictionary<String, ITestResult>;

Угадайте, зачем нам ключ String? Правильно, чтобы по нему добраться до ветки и сообщить о её состоянии после результата теста. Как по мне, перемудрили.

Отдельного упоминания заслуживает класс TTreeNode. Он в себе хранит «ссылку» на тест и картинку, которая будет изменять состояние ветки. Так как класс унаследован от TreeViewItem, такой код живет отлично:

var
   testNode : TTreeViewItem;  
   ...
   testNode := CreateNode(TestTree, test.Name, test.Fixture.FullName + '.' + test.Name);
   ...

function TGUIXTestRunner.CreateNode(Owner: TComponent; Text: String; TestFullName: String): TTreeViewItem;
begin
  Result := TTestNode.Create(Owner, Text, TestFullName);
end;
...
constructor TTestNode.Create(Owner: TComponent; Text, TestFullName: String);
begin
  inherited Create(Owner);
  Self.Text := Text;
  FFullName := TestFullName;
  FImage := TImage.Create(Owner);
  FImage.Parent := Self;
  {$IFDEF DELPHI_XE6_UP}
  FImage.Align := TAlignLayout.Right;
  {$ELSE}
  FImage.Align := TAlignLayout.alRight;
  {$ENDIF}
  FImage.Bitmap.Create(15, 15);
  FImage.Bitmap.Clear(TAlphaColorRec.Gray);
  FImage.SendToBack;
end;  

В целом DUnitX произвёл на меня хорошее впечатление. Фреймворк кажется намного солиднее своего старшего брата. Интерфейсы и архитектуру ребята пересмотрели и, думаю, даже улучшили. Весь код очень аккуратный. Комментариев больше в разы. Буду присматриваться и сравнивать.

Ссылки


Репозиторий Delphi-Mocks. Необходим для компилирования фреймворка;
Репозиторий DUnitX.
Tags:
Hubs:
+8
Comments 3
Comments Comments 3

Articles