What are Test Hooks?

Finally, the promised post.

Types of Controls

There are three types of controls you’ll discover when automating UI

  1. Standard Windows controls
  2. Owner-drawn controls – controls that have the functionality of Standard Windows controls, but have custom drawing. These controls will have to implement IAccessible to describe the custom paint job
  3. Painted controls – I’ve asked around what the term was, and everyone I asked responded with “they are just painted”. This is where there’s only one window, but within the window, numerous controls are painted.

How automation typically works

Automating UI requires three critical aspects:

  1. Capturing controls
  2. Manipulating controls
  3. Acquiring data from controls

These tasks can usually be achieved via Win32 API calls, MSAA, or in some cases, from the application’s object model when dealing with Standard Windows controls and Owner-drawn controls.

For example, consider capturing a regular button to verify its caption and what it does when clicked. You would first use a tool like Spy to find the control and to get information on the control, like its classname. From the automation framework, you would search for the window with this particular classname among all available windows to get its handle. Using the handle, you’ll be able to use Win32 API calls and MSAA calls to either manipulate the control, ie pressing the button using IAccessible::DoDefaultAction() or acquiring data from it, ie getting the button’s caption using GetWindowText().

But what happens if the control doesn’t have its own window?

Consider File Tabs on the File Tab Channel. See my post on the File Tab Channel for a picture of what this looks like. If you were to use Spy on the File Tab Channel, the first thing you’ll notice is that the individual file tabs do not have their own windows. There’s only one window (the File Tab Channel itself) that hosts the File Tabs. How does one capture the File Tabs if all of them are contained within the same window?

Use Test Hooks

Test hooks are “hidden” messages the developer will write into the application. I call these hidden because you have to ask the developer what messages to send to which window (or look at the code). The tester supplies the developer with a list of requirements, like being able to press the button or get the caption. And the developer in returns gives you back a set of messages to send to a given window that will produce the desired effect, like click the button or return the button’s caption.

Here’s how an automation framework might use the test hook to get the caption of a particular File Tab on the File Tab Channel.

Several things to note:

  1. SendMessage() is used to send messages to a control
  2. The WM_USER range is typically used to define custom messages to a particular custom control.
  3. ATOMs are useful when a string is needed by an external process, which is usually the case in an automation framework. ATOMs are global to Windows.

Const FileTabMessage As Integer = &H8000 + &H1001 ‘ WM_USER + test message app is expecting – note: this is just a number I made up

Const Text As Integer = 1

Const Click As Integer = 2

Private Function GetFileTabText(ByVal fileTabIndex As Integer) As String

‘ send message to test hook requesting the ATOM for the requested file tab’s caption

Dim atom As IntPtr = SendMessage(MainWindowHwnd, FileTabMessage, fileTabIndex, Text)

‘ convert ATOM to String

Dim buffer As New String(" "c, 255)

GlobalGetAtomName(atom.ToInt32, buffer, buffer.Length)

Return buffer.Substring(0, buffer.IndexOf(Nothing))

End Function