Question

I wrote a simple UI automation test for my application using Project White. It just launches the app and checks if the main window exists. This is done in the context of an NUnit test:

///AppTest.cs
[Test]
public void ShouldDisplayMainForm() {
   using( var wrapper = new WhiteWrapper( MYAPP_PATH ) ){
       Window win = wrapper.GetWindow( "MYAPP_MAIN_FORM_TITLE" );
       Assert.IsNotNull(win);
   }
}

///WhiteWrapper.cs
using System;
using White.Core;
using White.Core.Factory;
using White.Core.UIItems;
using White.Core.UIItems.WindowItems;

namespace MGClient.Test {

    internal class WhiteWrapper : IDisposable {
        private readonly Application mHost;
        private readonly Window mMainWindow;

        public WhiteWrapper( string pPath ) {
            mHost = Application.Launch( pPath );
        }

        public WhiteWrapper( string pPath, string pMainWindowTitle )
            : this( pPath ) {
            mMainWindow = GetWindow( pMainWindowTitle );
        }

        public void Dispose() {
            if( mHost != null )
                mHost.Kill();
        }

        public Window GetWindow( string pTitle ) {
            return mHost.GetWindow( pTitle, InitializeOption.NoCache );
        }

        public TControl GetControl<TControl>( string pControlName ) where TControl : UIItem {
            return mMainWindow.Get<TControl>( pControlName );
        }
    }
}

The problem is that the test results are random: sometimes it fails, sometimes it succeeds, without following a pattern.

The test environment is set so that initialization fails: I want to see the test fail consistently. The problem is that my app's main form performs its initialization and all related validations in the handler for its Load event. I think there is a race condition, due to the fact that White runs the application under test in a separate process:

When GetWindow is called before the initialization failure is detected, the test succeeds. When failure detection wins the race, it closes the app, so this makes GetWindow fail.

I'm looking through White documentation and browsing through samples, but I can't find a workaround for this scenario. Changing the app's code should be a last resort since I don't have a test harness yet (and that's what got me stuck: all my ideas revolve around changing the app).

Was it helpful?

Solution 2

I looked at White.Core.UIItems.WindowItems.Window's public interface and found the WaitTill method, which paired with the IsCurrentlyActive property did the trick:

///AppTest.cs
[Test]
public void ShouldDisplayMainForm() {
   using( var wrapper = new WhiteWrapper( MYAPP_PATH ) ){
       Window win = wrapper.GetWindow( "MYAPP_MAIN_FORM_TITLE" );
       Assert.IsNotNull(win);
       win.WaitTill( ()=> win.IsCurrentlyActive );
   }
}

Now the test always fails. Sometimes it times out in the GetWindow call, sometimes it does in WaitTill. But it always fails when initialization does, so that's good enough for me.

To other White noobs: documentation is pretty scarce, so bear with it and look at the source (if you find some good doc source, please do tell).

OTHER TIPS

Create a WaitHandle.
Add an event to Loaded which will reset the WaitHandle object.
In your test use WaitHandle.WaitOne(), which will cause it to sleep until Load is finished.

[Test]
public void ShouldDisplayMainForm() {
   using( var wrapper = new WhiteWrapper( MYAPP_PATH ) ){
       WaitHandle handle = new ManualResetEvent(false);
       Window win = wrapper.GetWindow( "MYAPP_MAIN_FORM_TITLE" );
       win.Loaded += (sender, e) => handle.set(); //Loaded or Onload, depending on framework
       handle.WaitOne();
       Assert.IsNotNull(win);
   }
}

There is a minor issue with this, if Loaded has already been called you will be waiting indefinitely.


You can check IsHandleCreated which will tell you if loading is complete. Here's a crappy solution that will work.

[Test]
public void ShouldDisplayMainForm() {
   using( var wrapper = new WhiteWrapper( MYAPP_PATH ) ){
       Window win = wrapper.GetWindow( "MYAPP_MAIN_FORM_TITLE" );
       While (win.IsHandleCreated)
         Thread.Sleep(1000);
       Assert.IsNotNull(win);
   }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top