понедельник, 4 ноября 2013 г.

О GUI-тестировании "по-русски". Развиваем тему

Предыдущая серия была тут - http://18delphi.blogspot.ru/2013/11/gui.html

Попробуем развить тему.

Давайте попробуем поработать с контролом в фокусе и например ввести в него текст.

Это можно сделать несколькими способами.

Например через эмуляцию нажатия кнопок или непосредственно присваивая свойство Caption/Text.

И тот и другой способ - имеют право на жизнь. И служат разным целям.

Эмуляция нажатия кнопок - проверяет как контрол обрабатывает клавиатурный ввод. Непосредственное присваивание позволяет управлять состоянием контрола, для проверки дальнейшей бизнес-логики приложений.

Это разные уровни тестирования. Об уровнях тестирования я может быть расскажу как-нибудь потом.

А пока реализуем слова тестовой машины для работы с контролами.

interface

TkwFocusedControl = class(TscriptKeyWord)
protected
 procedure DoIt(aContext : TscripContext); override;
end;//TkwFocusedControl

TkwEditSetText = class(TscriptKeyWord)
protected
 procedure DoIt(aContext : TscripContext); override;
end;//TkwEditSetText

implementation

procedure TkwFocusedControl.DoIt(aContext : TscripContext);
var
 l_Control : TControl;
begin
 l_Control := FindControl(Windows.GetFocus);
 Assert(l_Control <> nil);
 aContext.PushObject(l_Control);
end;

procedure TkwEditSetText.DoIt(aContext : TscripContext);
var
 l_Text : String;
 l_Control : TControl;
begin
 l_Control := aContext.PopObject;
 l_Text := aContext.PopString;
 Assert(l_Control Is TEdit);
 (l_Control As TEdit).Text := l_Text;
 // - это можно было бы сделать и через RTTI, но мы сделаем это напрямую
end;

initialization
 ScriptEngine.RegisterWord(TkwFocusedControl, 'FocusedControl');
 ScriptEngine.RegisterWord(TkwEditSetText, 'EditSetText');

Теперь напишем тест:

OBJECT VAR l_Control
FocusedControl =: l_Control
'Текст' l_Control EditSetText

Он делает, что и задумывалось - находит контрол в фокусе и присваивает ему заданный текст.

Теперь напишем вспомогательное слово:

PROCEDURE "Присвоить текст в текущий контрол" STRING IN aText
 OBJECT VAR l_Control
 FocusedControl =: l_Control
 aText l_Control EditSetText
END //"Присвоить текст в текущий контрол"

Тест теперь можно переписать так:

"Присвоить текст {('Текст')} в текущий контрол"

Опять же - "почти похоже" на кусок TestCase'а.

"На закуску" - реализуем слово для эмуляции нажатия на кнопку клавиатуры в контроле в фокусе.

Оно потом нам понадобится.

Вот это слово:

interface
 TkwKey = class(TscriptKeyWord)
  {* Нажатие на кнопку клавиатуры.
Пример:
[code]
PROCEDURE "Нажать" STRING IN aString
 aString Key
END // "Нажать"
[code] }
 protected
 // realized methods
   procedure DoIt(aContext: TscriptContext); override;
 end;//TkwKey

implementation

procedure TkwKey.DoIt(aContext: TscriptContext);
type
 TSS = ssShift..ssDouble;
const
 cMap : array [TSS] of Integer = (VK_Shift, VK_MENU, VK_Control,
                                  0, 0, 0, 0);
var
 l_SC : TShortCut;
 l_K  : Word;
 l_Shift: TShiftState;
 l_ShiftToCheck: TShiftState;
 l_H    : THandle;
 l_KeyState: TKeyboardState;
 l_NewKeyState: TKeyboardState;
 I : Integer;
 l_SS : TSS;
 l_AltOnly : Boolean;
 l_Alt : Boolean;
begin
 l_H := GetFocus;
 l_SC := TextToShortCut(aContext.PopString);
 Assert(l_SC <> 0);
 ShortCutToKey(l_SC, l_K, l_Shift);
 l_ShiftToCheck := l_Shift;
 l_AltOnly := false;
 l_Alt := false;
 l_Alt := ssAlt in l_ShiftToCheck;
 GetKeyboardState(l_KeyState);
 try
  for I := Low(l_NewKeyState) to High(l_NewKeyState) do
   l_NewKeyState[I] := 0;
  for l_SS := Low(l_SS) to High(l_SS) do
  begin
   if (l_SS in l_Shift) then
   begin
    if (cMap[l_SS] <> 0) then
    begin
     l_ShiftToCheck := l_ShiftToCheck - [l_SS];
     l_NewKeyState[cMap[l_SS]] := $81;
     SetKeyboardState(l_NewKeyState);
     if (cMap[l_SS] = vk_Menu) then
     begin
      //PostMessage(l_H, WM_KEYDOWN, cMap[l_SS], $20380001);
     end//cMap[l_SS] = vk_Menu
     else
      PostMessage(l_H, WM_KEYDOWN, cMap[l_SS], $1510001);
     ProcessMessages;
    end;//cMap[l_SS] <> 0
   end;//l_SS in l_Shift
  end;//for l_SS
  Assert(l_ShiftToCheck = []);
  l_NewKeyState[l_K] := $81;
  SetKeyboardState(l_NewKeyState);
  if l_AltOnly then
  begin
   SendMessage(l_H, WM_SYSCHAR, l_K, 0);
  end//l_AltOnly
  else
  begin
   if l_Alt then
    PostMessage(l_H, WM_SYSKEYDOWN, l_K, $20170001)
   else
    PostMessage(l_H, WM_KEYDOWN, l_K, $1510001);
   ProcessMessages;
   if l_Alt then
    PostMessage(l_H, WM_SYSKEYUP, l_K, $E0170001)
   else
    PostMessage(l_H, WM_KEYUP, l_K, $1510001);
   ProcessMessages;
  end;//l_AltOnly
  for l_SS := Low(l_SS) to High(l_SS) do
  begin
   if (l_SS in l_Shift) then
   begin
    if (cMap[l_SS] <> 0) then
    begin
     if (cMap[l_SS] = vk_Menu) then
     begin
      //PostMessage(l_H, WM_KEYUP, cMap[l_SS], $C0380001);
     end//cMap[l_SS] = vk_Menu
     else
      PostMessage(l_H, WM_KEYUP, cMap[l_SS], $1510001);
     ProcessMessages;
    end;//cMap[l_SS] <> 0
   end;//l_SS in l_Shift
  end;//for l_SS
 finally
  SetKeyboardState(l_KeyState);
 end;//try..finally
end;//TkwKey.DoIt

initialization
 ScriptEngine.RegisterKeyWord(TkwKey, 'Key');

Теперь напишем тест:

'Enter' Key
'Tab' Key
'Shift-Tab' Key

Ну и опять напишем "вспомогательное слово":

PROCEDURE "Нажать" STRING IN aString
 aString Key
END // "Нажать"

Тогда тест можно переписать так:

 "Нажать {('Enter')}"
 "Нажать {('Tab')}"
 "Нажать {('Shift-Tab')}"

Опять - "почти по-русски".

Мне кажется, что подобный "код" может читать и исполнять человек.

На этом - пока закончим.

Комментариев нет:

Отправить комментарий