понедельник, 16 марта 2015 г.

GUI-testing 8. About GUI-testing “in spoken style”. The follow-up

Original in Russian: http://18delphi.blogspot.ru/2013/11/gui_4.html

GUI-testing. Table of contents

We’ll try to follow up.

Let's try to work with focused control and, for example, input text to it.

This can be done in different ways.

For example, through the emulation of buttons pressing or setting the property Caption/Text.

Both ways worth considering and serve different purposes.

Emulation of buttons pressing checks how control processes keyboard input. The direct setting of property allows to manage the state of control in order to check the further business logic of the application.

These are the different levels of testing. May be I’ll tell about testing levels later.

Meanwhile, we’ll implement the words of testing engine to work with controls.

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;
 // - this could be done using RTTI, but we do it straight
end;
 
initialization
 ScriptEngine.RegisterWord(TkwFocusedControl, 'FocusedControl');
 ScriptEngine.RegisterWord(TkwEditSetText, 'EditSetText');

Now, we’ll write test:

OBJECT VAR l_Control
FocusedControl =: l_Control
'Text' l_Control EditSetText

The test does what it is supposed to do – it finds the focused control and assigns the specified text to it.

Now, we write auxiliary word:

PROCEDURE "Assign the text to the current control" STRING IN aText
 OBJECT VAR l_Control
 FocusedControl =: l_Control
 aText l_Control EditSetText
END //" Assign the text "

Now, we can rewrite the test in this way:

" Assign the text {('Text')} to the current control"

Again, it is “quite similar” to the fragment of TestCase.

“As a final treat” we’ll implement the word for emulation of pressing the keyboard button in focused control.

We’ll need it afterwards.

That’s the word:

interface
 TkwKey = class(TscriptKeyWord)
  {* Pressing the button on keyboard.
The example:
[code]
PROCEDURE "Press" STRING IN aString
 aString Key
END // "Press"
[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');

Now, we’ll write the test:

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

And again we’ll write “auxiliary word”:

PROCEDURE "Press" STRING IN aString
 aString Key
END // "Press"

Then, the test may be rewritten in this way:

"Press {('Enter')}"
"Press {('Tab')}"
"Press {('Shift-Tab')}"

Again – close to “the spoken style”.

It seems to me that such “code” is readable and executable.

I think we’ll close here for now.

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

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