竞争条件使集成测试不一致

时间:2013-06-05 18:14:44

标签: c# winforms race-condition white

我使用Project White为我的应用程序编写了一个简单的UI自动化测试。它只是启动应用程序并检查主窗口是否存在。这是在NUnit测试的上下文中完成的:

///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 );
        }
    }
}

问题是测试结果是随机的:有时它会失败,有时它会成功,而不会遵循模式。

设置测试环境以便初始化失败:我希望看到测试失败。问题是我的应用程序的主窗体在其Load事件的处理程序中执行其初始化和所有相关验证。我认为存在竞争条件,因为怀特在一个单独的过程中运行被测试的应用程序:

在检测到初始化失败之前调用GetWindow时,测试成功。当故障检测赢得比赛时,它会关闭应用程序,因此这会使GetWindow失败。

我正在查看White文档并浏览示例,但我无法找到此方案的解决方法。更改应用程序的代码应该是最后的手段,因为我还没有测试工具(这就是让我陷入困境的原因:我所有的想法都围绕着改变应用程序)。

2 个答案:

答案 0 :(得分:1)

创建WaitHandle
将事件添加到Loaded,这将重置WaitHandle对象 在您的测试中使用WaitHandle.WaitOne(),这将使其在Load完成之前进入休眠状态。

[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);
   }
}

这有一个小问题,如果已经调用了Loaded,你将无限期地等待。


您可以查看IsHandleCreated,它会告诉您加载是否完成。 这是一个可行的蹩脚解决方案。

[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);
   }
}

答案 1 :(得分:1)

我查看了White.Core.UIItems.WindowItems.Window的公共界面,发现与WaitTill属性配对的IsCurrentlyActive方法可以解决问题:

///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 );
   }
}

现在测试总是失败。有时它会在GetWindow调用中超时,有时会在WaitTill中执行。但是在初始化时总是会失败,所以这对我来说已经足够了。

对于其他白色新手:文档非常稀缺,所以请耐心看看来源(如果你找到一些好的文档来源,请告诉我们)。