Question

The scenario that I am facing is that I am trying to write a single test which will use Coded UI to interact with multiple instances of the same application, in this case Microsoft Excel. In other words, there will be multiple Excel workbooks open in multiple windows, and I need to be able to direct Coded UI to interact with a specific instance programatically. I initially thought this type of instance management would be a function of the ApplicationUnderTest class, but it is not obvious how this class would achieve this.

The interactions will involve the same UIMap for all instances (in fact, each instance will probably need multiple UIMaps, but for the sake of simplicity that can be ignored for this question unless it is significant to the answer).

A couple of solution approaches I'm already aware of:

  • Minimize and maximize the instances so only the one currently being used is visible at any given time. Ideally I'd like to avoid this. For one thing, it may eventually become a requirement that two windows are visible simultaneously during the tests.
  • Dynamically modify the search properties to always include some unique identifier every time the UI Map is accessed. I'm not sure what the best candidate for a search property would be here.

Ideally I would like something more integrated into Coded UI than either of these options, though the latter would probably suffice if necessary. I would appreciate any direction on whether there are any other possible approaches.

Was it helpful?

Solution

You could try creating multiple instances of the ui control (the class generated in the UIMap) and set an Instance search property for them (if you have any other unique search properties you can use those too). You only need to set these at the start of the test.

I used a calculator for this example. It should be Namespace.UIControl and not UIMap.UIControl. You need the class not the property.

var a1 = new UICalculatorWindow();
a1.SearchProperties["Instance"] = "1";
var a2 = new UICalculatorWindow();
a2.SearchProperties["Instance"] = "2";
a1.Find();
a2.Find();

After finding these windows their window handle will be associated with the control object so you don't have to worry about their order anymore.

Another solution would be to get all current window handles via a pinvoke function, filter these to get the windows you want, then use the UITestControlFactory to create your controls.


Edit: or you can use the FindMatchingControls method.

var a = new UICalculatorWindow().FindMatchingControls();

Then you can get the live controls from the returned list. These solutions are a bit workaround-ish but I don't think this can be solved on the UIMap level unless all instances of the control are recorded as unique ui controls.


Edit: CUIT searches in the list of window handles it gets from a WinApi call (EnumWindows) and by default it returns the first window from the list that matches the given search properties. If the Instance property is set then it skips the first n-1 windows (that matches the search criteria) and gets you the n-th window.

When you call Find() on a UITestControl it will search for a window with the given search properties and if a window is found the UITestControl keeps a reference to that window's window handle or the AccessibleObject it got from that window.

The order of window handles can change pretty often, for example if you set focus to a window it will be closer to beginning of the list. So when you have all your windows open you should create the UITestControls, set the Instance property and call Find() on all of them so they don't mix up during the test run.

If you find a window with Instance set to 1 and then mix up the order of the windows then when you search for a window with Instance set to 2 you might find the window you already found, ending up with two UITestControls set to the same window.

I have no idea how OrderOfInvocation works, I couldn't get it to work yet.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top