Visual Studio Team System Testing tools and multithreading

If you've been doing testing with Visual Studio Team System (VSTS) you have probably noticed that each test might be run in different thread. And the same is valid for set up and clean up methods. This feature might be a good one generally but not if you are testing UI.

I worked a scenario where I start application's main form within ClassInitializeAttribute decorated MyClassInitialize method. Then I do various tests in sequence (I use ordered tests) and finally I close the application in ClassCleanupAttribute decoreated MyClassCleanup method.

Here is a how my code looks (simplified):

private MainFrm mainFrm; // Form derived class [ClassInitialize()] public static void MyClassInitialize(TestContext testContext) { mainFrm = new MainFrm(); mainFrm.Show(); } [ClassCleanup()] public static void MyClassCleanup() { mainFrm.Dispose(); mainFrm = null; } [TestMethod] public void SomeTest() { // do some test with mainFrm }

Since I am using an ordered test to executes tests in sequence I would expect that tests are run in the same thread. However this is not the case nor you can force VSTS to use a single thread. Why is it important anyway? Because all operations to the UI have to be done within the thread that created UI control. Any access from different thread should and probably would cause an exception at best. Ouch, that's sounds like a showstopper for UI testing (besides the fact that VSTS doesn't support UI testing). To tell you the truth I was really surprised that an option to run tests in a single thread is missing.

So I start considering switching to NUnit (and TestDriven.net perhaps) since my tests weren't that many so far. The switch would cause me more work and more administration and I wasn't that happy to take NUnit path. Then I found the solution, which is really very simple. You have to execute all operations on UI thread and Control.Invoke method does exactly that. Here is modified code:

private MainFrm mainFrm; [ClassInitialize()] public static void MyClassInitialize(TestContext testContext) { // this method remains same - this thread creates UI mainFrm = new MainFrm(); mainFrm.Show(); } [ClassCleanup()] public static void MyClassCleanup() { // if thread is not one that created the form then excute an // Invoke call to switch thread if (mainFrm.InvokeRequired) mainFrm.Invoke(new MethodInvoker(MyClassCleanup)); else { mainFrm.Dispose(); mainFrm = null; } } [TestMethod] public void SwitchToFootball() { // if thread is not one that created the form then excute an // Invoke call to switch thread // Do the same if clause for any test that has to interact with UI classes // (indirectly or directly) if (mainFrm.InvokeRequired) mainFrm.Invoke(new MethodInvoker(SwitchToFootball)); else SwitchTo(BetCategoryCode.Football); }

Basically, before each test execution you have to make sure it executes in correct thread (the one that created UI objects). You do that by first checking whether the current thread has to be switched by checking Control.InvokeRequired property (both this property and Invoke method are thread safe). If this property is true you have to switch threads by invoking Control.Invoke method with a delegate to the method to execute (which is the same in this case) otherwise no switch is required. And you don't even have to create different delegate types since a test method has to be a parameterless method and thus System.Windows.Forms.MethodInvoker delegate is good for all methods.

And that's it. Happy UI testing.

Loading