1. Trang chủ
  2. » Công Nghệ Thông Tin

Effective GUI Test Automation Developing an Automated GUI Testing Tool phần 4 ppsx

46 218 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 46
Dung lượng 0,97 MB

Nội dung

121 Building a Dynamic Linking Library for GUI Testing The GetGUIInfoType() helper method returns a value of the GUIInfoType enumeration based on the known combination of the window text, the class name, and the parent window’s text. The recognition of such a combination is achieved by a set of if-else statements. As we have discussed, the last return statement assumes the window text is passed if no other vari- ables are known. Subsequently, it calls one more helper method, ResetGUIInfo(). The ResetGUIInfo() method is coded as in Listing 4.8. ➲ Listing 4.8 Code for the ResetGUIInfo() Helper Method] private static void ResetGUIInfo(GUIInfoType guiInfoType, ➥int hwnd, ref int hWndTarget, ➥ref string windowText, ref string className, ➥ref string parentText, StringBuilder sWindowText, ➥StringBuilder sClassname, StringBuilder sParentText) { string clsStartedWith = ""; if (className.IndexOf(".") >= 0) { clsStartedWith = ➥className.Replace(className.Split('.')[className.Split('.').Length-1], ""); } else { clsStartedWith = className; } if (guiInfoType == GUIInfoType.guiText) { if (sWindowText.ToString() == windowText) { hWndTarget = hwnd; className = sClassname.ToString(); parentText = sParentText.ToString(); } } else if (guiInfoType == GUIInfoType.guiTextClass ) { if (sWindowText.ToString() == windowText && sClassname.ToString().StartsWith(clsStartedWith)) { hWndTarget = hwnd; parentText = sParentText.ToString(); } } else if (guiInfoType == GUIInfoType.guiTextParent) { if (sWindowText.ToString() == windowText && sParentText.ToString() == parentText) 4351Book.fm Page 121 Tuesday, September 28, 2004 11:21 AM 122 Chapter 4 • Developing a GUI Test Library { hWndTarget = hwnd; className = sClassname.ToString(); } } else if (guiInfoType == GUIInfoType.guiTextClassParent) { if (sWindowText.ToString() == windowText && sClassname.ToString().StartsWith(clsStartedWith) && sParentText.ToString() == parentText) { hWndTarget = hwnd; } } else if (guiInfoType == GUIInfoType.guiClassParent) { if (sClassname.ToString().StartsWith(clsStartedWith) && sParentText.ToString() == parentText) { hWndTarget = hwnd; windowText = sWindowText.ToString(); } } } The first if statement of the ResetGUIInfo() truncates the last part of the given class name and assigns the result to a clsStartedWith variable when the class name is separated by a few periods (.) into several parts. This is because the Win32 API GetClassName() function finds the class names of the GUI controls in applications developed with .NET environment with the last part suffixed with an .appxx, in which the xx is a number varying from time to time. The later context will discuss this in more detail. The else statement places the given class name into the clsStartedWith variable in order that the GUI test library can test applications devel- oped in environments other than .NET. This helper method assigns the correct values to the unknown window text, the class name, and/or the parent window’s text within a few sections of if-else statements. These correct val- ues are found through each handle of the child windows. The outside if-else statements direct the program to a section of known variable combinations identified by the guiInfoType value. If the passed values from the FindGUILike() method match all the values found, the GUI object of interest is found and the unknown values of the window text, the class name, and/or its parent text become known. For example, the last else-if section deals with a situation in which the class name and the parent text of a GUI are known. When a GUI is found to have the same class name and the same parent text, the ResetGUIInfo() method assigns the GUI’s handle to the hWndTarget and the GUI’s text to the windowText variable. 4351Book.fm Page 122 Tuesday, September 28, 2004 11:21 AM 123 Building a Dynamic Linking Library for GUI Testing The last calling of the GetWindow() function by passing a value of the GW_HWNDNEXT constant continues to obtain each GUI handle until all the child windows are checked. After the while loop, the level value is decremented by 1, which drives the recursive calling of the FindGUILike() method until all the parent windows are checked. This is an exhaustive iteration; eventually all the GUI objects will be checked and the desired GUI object will be found. Before a person clicks a mouse button, they move the mouse pointer over a GUI object. How- ever, the test monkeys in Chapter 3 simply moved the mouse pointer and clicked randomly. The task of the code in Listing 4.6 is only to find a GUI handle. You want a method to drive the pointer to that GUI object and do something. A CenterMouseOn() method is implemented to pass the found handle as a parameter and move the mouse pointer to the center of the GUI object. Listing 4.9 is the implementation of the CenterMouseOn() method. ➲ Listing 4.9 Code for the CenterMouseOn() Method public static bool CenterMouseOn(int hwnd) { int x = 0; int y = 0; int maxX = 0; int maxY = 0; RECT crect = new RECT(); int gFound = 0; GetDisplayResolution(ref maxX, ref maxY); gFound = GetWindowRect(hwnd, ref crect); x = crect.Left + ((crect.Right - crect.Left) / 2); y = crect.Top + ((crect.Bottom - crect.Top) / 2); if ((x >= 0 && x <= maxX) && (y >= 0 && y <= maxY)) { MoveMouse(hwnd, x, y); return true; } return false; } The goal of the CenterMouseOn() method is to move the mouse pointer to a coordinate point that will be found by executing some custom functions. It first prepares an x- and a y- variable to find the central coordinate of a GUI object. Then it prepares two more variables, maxX and maxY, to make sure the x- and the y-axes of the display screen has as its maximum number of pixels. A RECT object is initialized to hold the pixels to define a rectangle of the GUI object of interest. Finally, a gFound variable makes sure the GUI object of interest is open in the current desktop session. After the preparation, various functions are executed to assign values to the respective variables. The first helper method is GetDisplayResolution() and it is coded in Listing 4.10. 4351Book.fm Page 123 Tuesday, September 28, 2004 11:21 AM 124 Chapter 4 • Developing a GUI Test Library ➲ Listing 4.10 Code for the GetDisplayResolution() Helper Method public static void GetDisplayResolution(ref int pixelX, ref int pixelY) { pixelX = GetSystemMetrics(SM_CXSCREEN); pixelY = GetSystemMetrics(SM_CYSCREEN); } This method simply calls the GetSystemMetrics() function two times to find the width and height of a display screen. These pixel values are the maximum measurements for any windows. Knowing this information ensures that all the testing actions occur within the screen. Then the GetWindowRect() method is called to locate the relative coordinate points of the upper-left and the lower-right corners of the GUI under test within a screen. These two corners determine a rectangle. The coordinates are stored in the RECT object passed by reference. After the rectangle of the GUI under test is found within the displayable area of the screen, the CenterMouseOn() method starts to count from the left edge toward the right to the halfway across the width of the found rectangle and assigns a value to the x variable for the central point in the x-axis. Then it starts from the top edge downward to the halfway point of the height of the GUI object and assigns a value to the y variable for the central point in the y-axis. The if statement confirms that the central point is inside the display screen and calls the MoveMouse() function to accomplish the movement of the mouse pointer to the center of the GUI under test. After the mouse is moved, a true value is returned. If the calculated x and y values fall beyond the screen, a false value is returned. You implemented a method to make the mouse perform an absolute movement relative to the screen in Chapter 3 and a CenterMouse() method to move the mouse to the center of a GUI. People also move the mouse pointer to any point inside a GUI rectangle. Listing 4.11 is the code to achieve such a mouse movement. ➲ Listing 4.11 Code for the MoveMouseInsideHwnd() Method public static void MoveMouseInsideHwnd(int hwnd, ➥int xPos, int yPos, RectPosition rctPos) { int xPixel = xPos; int yPixel = yPos; if (!rctPos.Equals(RectPosition.AnySpot)) { xPixel = 5; yPixel = 5; } CenterMouseOn(hwnd); int width = 0; 4351Book.fm Page 124 Tuesday, September 28, 2004 11:21 AM 125 Building a Dynamic Linking Library for GUI Testing int height = 0; POINTAPI pa = new POINTAPI(); GetWindowSize(hwnd, ref width, ref height); GetCursorPos(ref pa); switch (rctPos) { case RectPosition.LeftTop: xPixel = (pa.x - width/2) + xPixel % width ; yPixel = (pa.y - height/2) + yPixel % height; break; case RectPosition.LeftBottom: xPixel = (pa.x - width/2) + xPixel % width ; yPixel = (pa.y + height/2) - yPixel % height; break; case RectPosition.RightTop : xPixel = (pa.x + width/2) - xPixel % width ; yPixel = (pa.y - height/2) + yPixel % height; break; case RectPosition.RightBottom: xPixel = (pa.x + width/2) - xPixel % width ; yPixel = (pa.y + height/2) - yPixel % height; break; case RectPosition.MiddleTop : xPixel = (pa.x); yPixel = (pa.y - height/2) + yPixel % height; break; case RectPosition.MiddleBottom: xPixel = (pa.x); yPixel = (pa.y + height/2) - yPixel % height; break; case RectPosition.AnySpot: xPixel = (pa.x - width/2) + xPixel % width ; yPixel = (pa.y - height/2) + yPixel % height; break; } MoveMouse(hwnd, xPixel, yPixel); } The MoveMouseInsideHwnd() method takes four parameters, the GUI handle, hwnd, the x- and y-coordinates by pixel, and the GUI position, rctPos, you want the mouse pointer to move to. After the method declaration, the initialization of the xPixel and yPixel get the x- and y-coordinates, respectively. If the value of the rectPos parameter is not RectPosition.AnySpot, the MoveMouseInsideHwnd() method requests that the method move the mouse pointer at least 5 pixels inside the boundary of a GUI under test. Then, based on the handle passed as the first parameter, it calls the CenterMouseOn() method to move the mouse to the center of the GUI 4351Book.fm Page 125 Tuesday, September 28, 2004 11:21 AM 126 Chapter 4 • Developing a GUI Test Library object of interest. Next, the method continues to initialize three other variables—width, height, and a POINTAPI object, pa—for finding the width and height of the current GUI and the current mouse position by calling GetWindowSize() and GetCursorPos() methods respectively. The GetWindowSize() helper method determines the numbers of pixels of a GUI in both horizontal and vertical directions. Code for the GetWindowSize() method is shown in Listing 4.12. ➲ Listing 4.12 Code for the GetWindowSize() Method public static void GetWindowSize(int iHandle, ref int wPixel, ref int hPixel) { int lrC = 0; RECT rCC = new RECT(); lrC = GetWindowRect(iHandle, ref rCC); wPixel = rCC.Right - rCC.Left; hPixel = rCC.Bottom - rCC.Top; } This method simply calls the GetWindowRect() method to find the edge of a GUI rectangle in absolute pixel numbers within a screen. These absolute pixel numbers are stored in the rCC object as coordinates of the upper-left and lower-right corners. The difference between the absolute right and absolute left edge is the width of the GUI under test. The difference between the absolute top and bottom edge is the height of the GUI. The pixel values of width and height of the GUI are used to reset the wPixel and hPixel parameters passed by references. At this point, the MoveMouseInsideHwnd() method knows the size of the GUI of interest and the coordinate pixels of the current mouse pointer, which has been moved to the center of the GUI of interest. Last, a switch statement is used to check the value of the last parameter, that is, where the tester wants to move the mouse pointer for the next step. The mouse pointer can be moved to LeftTop, LeftBottom, RightTop, RightBottom, MiddleTop , MiddleBottom, or AnySpot inside the GUI and the absolute pixels can be calculated with regard to the entire screen area. But it will always be inside the GUI of interest at least 5 pixels toward the closest edges. The last statement invokes the MoveMouse() method and simply moves the mouse pointer from the center to the desired location inside the GUI. The hard part of GUI test automation is that the tools don’t know there are GUI compo- nents in an application. The capture/playback facility uses a pure manual process to com- pensate for this. The automatic GUI testing tool to be developed in this book will use an approach to move the mouse pointer systematically and pixel by pixel inside a GUI under test and determine the presence of a GUI at the current mouse position. In order to achieve this, you need to add a GetWindowFromPoint() method to the GUITestLibrary project. Code for the GetWindowFromPoint() method is in Listing 4.13. Thus, when the tool instructs the mouse to move around the display, it encounters all the GUI components within the application under test and obtains the information for a GUI test. 4351Book.fm Page 126 Tuesday, September 28, 2004 11:21 AM 127 Building a Dynamic Linking Library for GUI Testing ➲ Listing 4.13 Code for the GetWindowFromPoint() Method public static void GetWindowFromPoint(ref int hwnd, ➥ref StringBuilder winText, ref StringBuilder clsName, ➥ref StringBuilder pText) { int parentHandle = 0; int maxLen = 128; POINTAPI pnt = new POINTAPI(); parentHandle = GetCursorPos(ref pnt); hwnd = WindowFromPoint(pnt.x, pnt.y); winText = new StringBuilder(maxLen); parentHandle = GetWindowText(hwnd, winText, maxLen); clsName = new StringBuilder(maxLen); parentHandle = GetClassName(hwnd, clsName, maxLen); pText = new StringBuilder(maxLen); parentHandle = GetParent(hwnd); parentHandle = GetWindowText(parentHandle, pText, maxLen); } The GetWindowFromPoint() method manipulates four reference parameters: the handle, text, class name, and parent text of the GUI the mouse pointer is currently on. When the method is invoked, it first initializes two integer variables; the parentHandle variable is pre- pared to find the parent window and the maxLen variable is to set the function to make the maximum length of the text to 128 characters for each of the StringBuilder parameters passed as references. Then an initialization of a POINTAPI object, pnt, is used to locate the current position of the mouse pointer by the invocation of the GetCursorPos() function and get the GUI handle by invoking the WindowFromPoint() function. Once the handle of the GUI at the current mouse position is obtained, the code simply invokes the respective func- tions to assign text, class name, and parent text of the current GUI object to the reference parameters. To indicate the physical GUI unit from the GUI survey collected by the tool, you have prepared three constants—IDANI_CAPTION, IDANI_CLOSE, and IDANI_OPEN—and a DrawAnimatedRects() custom function for GUI animation. When the DrawAnimatedRects() method is invoked, the corresponding GUI object on the screen will blink a few times when the tester selects a property of a GUI object of a survey list. To handle this feature properly, you can code an Indicate- SelectedGUI() method as shown in Listing 4.14. 4351Book.fm Page 127 Tuesday, September 28, 2004 11:21 AM 128 Chapter 4 • Developing a GUI Test Library ➲ ➲ Listing 4.14 Code for GUI animation of the IndicateSelectedGUI() Method public static void IndicateSelectedGUI(int hwnd) { int xSize = 0; int ySize = 0; RECT rSource = new RECT(); GetWindowRect(hwnd, ref rSource); GetWindowSize(hwnd, ref xSize, ref ySize); SetRect(ref rSource, rSource.Left, rSource.Top, ➥rSource.Left + xSize, rSource.Top); DrawAnimatedRects(hwnd, ➥IDANI_CLOSE | IDANI_CAPTION | IDANI_OPEN, ref rSource, ref rSource); } The IndicateSelectedGUI() method yanks the handle of a GUI. At execution, it invokes the GetWindowRect() function to determine the rectangle position of the GUI by assigning a RECT object to the rSource object. Then it invokes the GetWindowSize() method to determine the width and height of the rectangle. After the rectangle of the GUI is known, the SetRect() function makes another rectangle to draw the GUI from its original position to the reset position. Then the last line of the code invokes the DrawAnimatedRects() method and completes the animation. The animation effect shows the window text of the GUI over a blue bar and blinks a few times. The already implemented methods are for GUI actions in general. The last part of this sec- tion will implement particular methods to handle particular GUI controls, such as how to click a ListBox, a command Button and a TextBox. Listing 4.15 is the code to click the vertical scroll bar and select an item from the list box. Listing 4.15 The Code of the HandleListBox() Method to Click a Vertical Scroll Bar and Select an Item from a List Box. public static void HandleListBox(ref int hwnd, ref string winText, ➥ref string clsName, ref string pText) { int r = GUITestActions.FindGUILike(ref hwnd, ➥0, ref winText, ref clsName, ref pText); CenterMouseOn(hwnd); MoveMouseInsideHwnd(hwnd, RectPosition.RightBottom); ClickMouse(MonkeyButtons.btcLeft,0,0,0,0); MoveMouseInsideHwnd(hwnd, RectPosition.MiddleBottom); ClickMouse(MonkeyButtons.btcLeft,0,0,0,0); } 4351Book.fm Page 128 Tuesday, September 28, 2004 11:21 AM 129 Building a Dynamic Linking Library for GUI Testing As discussed in the previous sections, the FindGUILike() method uses various combinations of a window’s text, its class name, and its parent window’s text to determine a known GUI in the desktop. The HandleListBox() method uses the combination of the class name and its parent window text to locate the handle of a ListBox control in an application under test. Then it calls the respective static methods to move the mouse to the center of the ListBox control. Then, it clicks the mouse button at the lower-right corner to scroll the vertical bar. Last, it clicks at the middle point near the lower edge of the list box to select the bottom item visible from the list box. Another often-performed GUI action is to click a command button. For example, when test- ing the C# API Text Viewer, after an item is selected in the list box, you need a method to click the Add button and append the function declaration to the rich text box. Listing 4.16 shows the code for the HandleCommandButton() method. ➲ Listing 4.16 The Code of the HandleCommandButton() Method public void HandleCommandButton(ref int hwnd, ➥ref string winText, ref string clsName, ref string pText) { int r = GUITestActions.FindGUILike(ref hwnd, ➥0, ref winText, ref clsName, ref pText); CenterMouseOn(hwnd); ClickMouse(MonkeyButtons.btcLeft, 0,0,0,0); } Similar to how a ListBox control is handled, the HandleCommandButton() method also uses the combination of the window’s text and its parent window’s text to locate a button handle of an application under test. The functions employed to click a button and click a list box are the same. But the invocation of the CenterMouseOn() and ClickMouse() methods occurs only once when a command button is clicked. The ClickMouse() method needs to be invoked twice for a ListBox control. The next method is to handle a click inside a TextBox control as well as a RichTextBox control. As the book progress, more methods will be needed to handle various GUI controls. Listing 4.17 shows the code for the HandleTextBox() method. ➲ Listing 4.17 The Code of the HandleTextBox() Method public static void HandleTextBox(ref int hwnd, ➥ref string winText, ref string clsName, ref string pText) { int r = FindGUILike(ref hwnd, 0, ref winText, ref clsName, ref pText); 4351Book.fm Page 129 Tuesday, September 28, 2004 11:21 AM 130 Chapter 4 • Developing a GUI Test Library CenterMouseOn(hwnd); MoveMouseInsideHwnd(hwnd, 20, 10, RectPosition.AnySpot); ClickMouse(MonkeyButtons.btcLeft,0,0,0,0); } As you can see, this method requires the same set of parameters and employs the same meth- ods as the ListBox and Button control handling methods do. The difference is the position in which the mouse button needs to be clicked. The HandleTextBox() method is implemented to click at the upper-left corner inside a TextBox. After the click, the TextBox gets the focus and the cursor is at the first line of the text. A method to handle synchronization for GUI testing is also implemented in this section. When we perform non-GUI testing, the execution of one line of code in the test script can be completed instantly and in sequence. But GUI testing actions often trigger new GUI compo- nents to show on the screen, and the next action is to interact with the new GUI components. Usually, there is some time elapsed before the required GUIs are completely drawn. This is the synchronization issue. If the execution of the next action is not synchronized with the appear- ance of the new window on the screen, the action can not be performed as desired. Thus, you need to implement a SynchronizeWindow() method such as in Listing 4.18. ➲ Listing 4.18 Code for the SynchronizeWindow() Method public static void SynchronizeWindow(ref int hwnd, ➥ref string winText, ref string clsName, ref string pText) { int startSyn = DateTime.Now.Second; while (hwnd <=0) { FindGUILike(ref hwnd, 0, ref winText, ref clsName, ref pText); if (5 < DateTime.Now.Second - startSyn) { break; } } } First, it marks an integer startSyn variable with the time, in seconds, that the action starts. Then it uses a while loop to execute the FindGUILike() method iteratively until the handle of the GUI control is found. In order to prevent an infinite loop (if, for example, a GUI of interest never shows on the screen), an if statement checks the time elapsing. The maximum time to loop is arbitrarily set to 5 seconds. You can choose a suitable elapsing time for your own testing requirements. 4351Book.fm Page 130 Tuesday, September 28, 2004 11:21 AM [...]... a GUI Test Library The ultimate goal of this book is to develop an AutomatedGUITest tool to automatically generate fully functional test scripts and complete the GUI test of an application with minimum human interaction Chapter 5 will introduce the serialization, reflection and late binding within the NET Framework Then, we will add more functions to the GUI test library and increase the degree of automation. .. the form contains an XML document with the branches and nodes fully expanded You can collapse or expand a node by clicking on the -/+ sign The expanded GUITestActionLib.xml document is shown in the TreeView control in Figure 5.2 FIGURE 5.2 Viewing the GUITestActionLib.xml document by navigating with an XmlDocument instance and a TreeView control 150 Chapter 5 • NET Programming and GUI Testing This XML... the book You can upgrade the GUI testing tool by implementing more powerful methods to enhance software test automation for your organization NOTE The full list of source code for the sample projects can be downloaded from www.sybex.com You can find the sample projects grouped by chapter Object Serialization Today, software applications tend to treat data as objects We want the GUI testing tool to recognize... way The last section of this chapter will introduce more advanced uses of a thread XML Programming This book focuses on techniques that are useful for developing an automatic GUI testing tool Because testers prefer a data-driven testing tool, it makes sense to employ Extensible Markup Language (XML) programming first XML is a broad and important topic in today’s software industry This section will not... helper method takes the XmlTextWriter instance, the name of the GUI class, and the 142 Chapter 5 • NET Programming and GUI Testing name of the GUI testing method as parameters The three lines of code inside the helper method simply invoke the three methods to create a start tag for each GUI class name, assign a string value of the method name to the element, and close the tag, respectively The WriteChildElement()... method and creates six nodes to properly use the methods of the GUI test library The GUI test library will grow as the testing tool created , you will have more chances to revisit this example and add more element tags and method names Finally, the WriteEndElement() method closes the root element The XML file is completed After all the code is added to the program, you can press F5 to build and run... for many purposes other than for marshaling custom functions with regard to GUI testing However, Win32 API programming thrives on the backbone of a programming language In Chapters 3 and 4, I assumed that you have some basic knowledge about C# NET programming Chapter 3 guided you through the development of a C# API Text Viewer Then you laid a foundation for the GUI testing library in Chapter 4 In order... upcoming chapters The automatically generated test scripts will eventually include code for verification, validation, and test presentation Chapter 5 NET Programming and GUI Testing 138 Chapter 5 • NET Programming and GUI Testing he previous two chapters have included a review of Win32 custom DLLs and their functions Software developers have a long history of using an API Text Viewer to help with the Win32... testing tool to recognize the testing cases and the GUI components under test as objects too The object serialization of the NET Framework suits this purpose well Later, the serialized objects can be deserialized , reconstructed and used for verification and regression testing Modern programming languages have built-in functions that can easily make objects persistent and store them in a physical file... flexible in XML and can be customized to suit almost all situations The following are the testing- tool- related definitions of the parts of XML needed to form a well-structured XML document: Attribute A property of an XML element An attribute has a name and a value to provide additional data about an element, independent of element content Element The basic unit of an XML document A start and an end tag . can code an Indicate- SelectedGUI() method as shown in Listing 4. 14. 43 51Book.fm Page 127 Tuesday, September 28, 20 04 11:21 AM 128 Chapter 4 • Developing a GUI Test Library ➲ ➲ Listing 4. 14. physical GUI unit from the GUI survey collected by the tool, you have prepared three constants—IDANI_CAPTION, IDANI_CLOSE, and IDANI_OPEN—and a DrawAnimatedRects() custom function for GUI animation objects by serialization and deserialization will help the GUI testing tool create and save the testing cases and present and save the test results. These data objects and results will all be

Ngày đăng: 12/08/2014, 21:20

TỪ KHÓA LIÊN QUAN