MSDN Magazine - March 2009 - (Page 43) Box, the controls do not receive Name properties, so I cannot use the same NameProperty pattern that I used for the Button control. However, the TextBox controls do receive an AutomationId property that I could use to get a reference to the controls, such as: aeTextBox1 = aeCryptoCalc.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, “textBox1”)); Instead, I decided to use a different approach, mostly for demonstration purposes. Rather than identify a single control using the control’s name property, I use the FindAll method to fetch a collection of controls by control type. It turns out that TextBox controls are ControlType.Edit types, so my code grabs all TextBox controls: AutomationElementCollection aeAllTextBoxes = null; aeAllTextBoxes = aeCryptoCalc.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit)); if (aeAllTextBoxes == null) throw new Exception(“No textboxes collection”); else Console.WriteLine(“Got textboxes collection”); Microsoft UI Automation library. You can think of pattern objects as an abstraction to expose a control’s functionality that is independent of the control’s type or appearance. Put another way, you can use specific AutomationPattern instances such as ValuePattern to enable specific control functionality. I simplify things further by thinking that a control’s ControlType exposes what kind of control the control is and that a control’s Pattern exposes what the control can do. I use a similar approach to simulating a user selecting the RadioButton control: Console.WriteLine(“Selecting ‘DES Encrypt’ “); SelectionItemPattern spSelectRadioButton3 = (SelectionItemPattern)aeRadioButton3.GetCurrentPattern( SelectionItemPattern.Pattern); spSelectRadioButton3.Select(); Once I have this collection I can access each TextBox using array indexing: AutomationElement aeTextBox1 = null; AutomationElement aeTextBox2 = null; aeTextBox1 = aeAllTextBoxes[0]; aeTextBox2 = aeAllTextBoxes[1]; if (aeTextBox1 == null || aeTextBox2 == null) throw new Exception(“TextBox1 or TextBox2 not found”); else Console.WriteLine(“Got TextBox1 and TextBox2”); This time I use the SelectionItemPattern to enable a selection. The name of the GetCurrentPattern method sometimes confuses MUIA library beginners. From a test automation point of view, the method is setting, not getting, a specified AutomationPattern. But from a client-server perspective, the automation client code is fetching a particular property from the application under test server code. The code I use to simulate a click on the Calculate button control should help clarify: Console.WriteLine(“\nClicking on Compute button”); InvokePattern ipClickButton1 = (InvokePattern)aeButton.GetCurrentPattern( InvokePattern.Pattern); ipClickButton1.Invoke(); Thread.Sleep(1500); In general, obtaining control references by using the Name property or the AutomationId property is a better approach than using ControlType, but in some scenarios you may have no choice. Next, I get a reference to the RadioButton control I want to use in my test scenario: AutomationElement aeRadioButton3 = null; aeRadioButton3 = aeCryptoCalc.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, “DES Encrypt”)); if (aeRadioButton3 == null) throw new Exception(“No RadioButton”); else Console.WriteLine(“Got RadioButton3”); I use a pattern similar to the one I used to get a reference to the Button control. However, notice that I specify TreeScope.Descendants rather than TreeScope.Children. I do this because the RadioButton control is a child of the GroupBox control and so is not a direct child of the main Window control. Alternatively, I could have first obtained a reference to the GroupBox control (as a child of the main Window control) and then used that reference to obtain a reference to the RadioButton control. Once I have references to my controls, I can start manipulating the application under test. I begin by simulating user input into the TextBox control: Console.WriteLine(“\nSetting input to ‘Hello1!’”); ValuePattern vpTextBox1 = (ValuePattern)aeTextBox1.GetCurrentPattern(ValuePattern.Pattern); vpTextBox1.SetValue(“Hello!”); Here, in essence, I use the InvokePattern to enable a button click and then execute the click by using the Invoke method. Notice I pause . seconds to give my application time to respond. I could also go into a delay loop, checking periodically to see if the result textBox field is empty or not. At this point in my test automation code, I have launched the application under test, entered “Hello!” into the input TextBox control, selected the DES Encrypt RadioButton control, and clicked on the Compute Button control. Now I examine the TextBox control to see if I have a correct expected value: Console.WriteLine(“\nChecking TextBox2 for ‘91-1E-84-41-67-4B-FF-8F’”); TextPattern tpTextBox2 = (TextPattern)aeTextBox2.GetCurrentPattern(TextPattern.Pattern); string result = tpTextBox2.DocumentRange.GetText(-1); Here I use TextPattern to prepare a call to a GetText method. Notice that I call GetText indirectly through a DocumentRange property, which returns a text range that encloses the main text of a document, in this case, a single text box. The - argument to GetText is used so that there is no maximum limit on the length of the return string. An alternative way to read the contents of the TextBox control is to use the GetCurrentPropertyValue method: string result = (string)aeTextBox2.GetCurrentPropertyValue(ValuePattern. ValueProperty); Using a SetValue method probably does not come as a surprise, but notice that I do not access SetVaue() directly through the aeTextBox object. Instead, I use an intermediary ValuePattern object. The concept of AutomationPattern objects such as ValuePattern is probably the biggest conceptual hurdle for engineers new to the msdnmagazine.com I have hardcoded the test case input into the test harness. A more flexible approach is to read test case input and expected values from some external data store. Now, with the actual value of the application under test in hand, I check against an expected value to determine my test scenario pass/fail result: March 2009 43 http://www.msdnmagazine.com
For optimal viewing of this digital publication, please enable JavaScript and then refresh the page. If you would like to try to load the digital publication without using Flash Player detection, please click here.