locked
Coded UI Tests: How do I perform multithreaded UI tests? RRS feed

  • Question

  • How do I perform multithreaded UI tests?

    Our application displays an image. The application has an indicator that turns orange while the image data is streaming and green when it is complete. The image streams when initially loading, zooming, and panning.

    In my UI Tests, I want to perform one of these actions and ensure that while that action is occurring (continuously zooming to the highest magnification, or performing a long pan) the image load indicator changes from green (initially loaded) to orange (streaming the new parts) and back to green (load completed for the new view).

    I would usually write a test that started a background thread to watch the indicator and the foreground thread would perform the (blocking) action. Consider this code an abstraction over UITestControls and Mouse/Keyboard methods (`viewer` is the application window).

        [TestMethod]
        public void StreamingIndicatorChangesWhenZooming()
        {
            var changed = false;
            var waitHandle = new ManualResetEvent(false);
            ThreadPool.QueueUserWorkItem(o =>
                {
                    var initial = viewer.Streaming;
                    while(true)
                    {
                        changed = viewer.Streaming == initial;
                        if(changed)
                            break;
                    }

                    waitHandle.Set();
                });

            viewer.ZoomIn(ZoomLevel.TwentyX);
            waitHandle.WaitOne(timeout);

            Assert.IsTrue(changed);
            Assert.AreEqual(StreamingIndication.Complete, viewer.Streaming);
        }

    However, I get the following exception

        One of the background threads threw exception:
        Microsoft.VisualStudio.TestTools.UITest.Extension.UITestException: The Coded UI Test is running in Single Threaded Apartment (STA) mode of COM. in this mode, all the playback calls hsould happen from the TestMethod thread only and UITestControl should not be shared across TestMethods.

    I realized the UITestControl underlying the Streaming control property was being lazy-loaded on the background thread. Adding an Assert on the TestMethod to load the control in that thread

        [TestMethod]
        public void StreamingIndicatorChangesWhenZooming()
        {
            Assert.AreEqual(StreamingIndication.Complete, viewer.Streaming);
            ...

    produced the following exception

        One of the background threads threw exception:
        Microsoft.VisualStudio.TestTools.UITest.Extension.UITestControlNotAvailableException: The control is not available or not valid. ---> Microsoft.VisualStudio.TestTools.UITest.Extension.UITestException: The Coded UI Test is running in Single Thread Apartment (STA) mode of COM.  In this mode, all the playback calls should happen from the TestMethod thread only and UITestControl should not be shared across TestMethods.

    I changed the ThreadPool to a Thread and set the apartment state to MTA and that produced the same exceptions. Is there any way to watch UI elements that are changing during blocking calls? Can I make the Coded UI Test run in MTA? For that matter, is there any way to setup events through the Automation framework? Am I stuck polling? and then, only polling non-blocking calls?
    Monday, January 18, 2010 7:49 PM

All replies

  • The MTA is not supported by Coded UI Test.  The playback operations can not be performed in background thread.
    Tuesday, January 19, 2010 2:11 PM
  • So, what options do I have to watch and assert on asynchronous UI events?
    Tuesday, January 19, 2010 6:43 PM
  • You can solve your problem by writing your code this way -

    The main thread will have the code similar to:- 

                    workerThreadEvent.WaitOne();
                    while (this.actionCode != ActionCode.Cleanup)
                    {
                        try
                        {
                            switch (this.actionCode)
                            {
                                case ActionCode.XXX:
                                    {
                                        // do XXX
                                        break;
                                    }

                                case ActionCode.YYY:
                                    {
                                       // do YYY
                                       
                                        break;
                                    }

                                default:
                                    break;
                            }
                        }
                        catch (UITestException ex)
                        {
                           // handle UI Test exception like ContolNotFound, ControlNotAvailable etc
                        }

                        workerThreadEvent.WaitOne();
                    }

            enum ActionCode
            {
                XXX,
                YYY,
                Cleanup,
            }

    If other threads need the playback operation XXX then it would do like
    this.actionCode = ActionCode.XXX;
    workerThreadEvent.Set();

    And the implmention of XXX will be there in the main thread loop.

    Wednesday, January 20, 2010 6:01 AM
  • I don't understand what this code is doing... are the Action Codes representative of the blocking action I want to perform (zooming)? Where are we capturing and asserting the async property?
    Wednesday, January 20, 2010 4:45 PM
  • Suppose you want to assert of some property in background thread then the code of the background thread will look like -

    this.actionCode = ActionCodes.Assert;
    workerThreadEvent.Set();
    backgroundThreadEvet.Wait();
    This will make the backgroudn thread to wait till the main thread has done the assertion operation. If you don want to make the background thread to be blocking the then dont use the last wait() call from the background thead.

    And the the code in switch sttement of main thread will be:-
     case ActionCode.XXX:
                                    {
                                        AssertOnTheControl();
                                        backgroundThreadEvent.Set();

                                        break;
                                    }

    void  AssertOnTheControl()
    {
         // do the assetion of whatever property you want
    }

    Monday, January 25, 2010 5:43 AM
  • This does not address my problem. I am not explaining it well. Let me start over...

    I need to perform a blocking operation on my application UI. For example, zooming several times in a row (clicking a button) or panning the image for an extended period of time (dragging a control). While these blocking operations are being executed by UI Automation/Coded UI Tests, another control's property is changing from an initial state to a "streaming" state and back to an initial state.

    I cannot simply check that control's property at the end of my blocking operation. I need to ensure that it has changed while performing the blocking operation . This is why using UI Automation and Coded UI Tests on a background thread was my first effort.

    You mentioned that Playback is not supported on a background thread. Does playback include simply reading a property (what if I initialize the control on the foreground thread)? Will the release version have support for this kind of test? Can UI Automation/Coded UI Tests get an event model to indicate properties changing (like the Automation Peers do)?
    Friday, January 29, 2010 7:16 PM
  • have you managed to solve this issue ,i would like to do the same 
    Ahmed Ismaiel
    Saturday, June 26, 2010 4:55 PM
  • I am in the same boat in regards to needing to be able to multi thread a task against IE.  Basically we have about 200 of the same objects on a page but with different innertext values and I want to be able to thread off getting all that data instead of running the same function 200 times sequentially which takes about 8 minutes.  I would like to do in concurrently so that it would take 15 seconds total instead of each.  However anytime time the function (now in a new thread via a foreach loop) hits a call to the browser (even though it is NOT performing a UI action, just getting data), I get:  "The Coded UI Test is running in Single Thread Apartment (STA) mode of COM.  In this mode, all the playback calls should happen from the TestMethod thread only and UITestControl should not be shared across TestMethods. (blah blah blah).  Thoughts?
    Thursday, March 8, 2012 6:18 PM
  • there is a known bug in 2010 where it won't work on any other browser setting zoom > 100 %.

    I found this very early on and according to MS it's working as designed yet I'm told in 2012 it works on other zooms

    Thursday, October 11, 2012 8:07 PM