当订单包含在有序测试中时,会收到UITestControlNotAvailableException

时间:2014-01-04 18:38:42

标签: wpf mstest coded-ui-tests specflow ordered-test

我使用 SpecFlow 编码的用户界面 WPF 应用程序创建一些自动功能测试。使用 MsTest Visual Studio Premium 2012 执行测试用例执行。

我有很多测试用例。如果我逐一执行它们一切都OK。如果我将它们全部放入有序测试中,我会收到以下错误:

Microsoft.VisualStudio.TestTools.UITest.Extension.UITestControlNotAvailableException: The following element is no longer available: Name [], ControlType [Custom], AutomationId [reags:LoadView_1], RuntimeId [7,1620,64780193] ---> System.Windows.Automation.ElementNotAvailableException: The following element is no longer available: Name [], ControlType [Window], AutomationId [UnitializedCB3702D1-14B6-4001-8BC7-CD4C22C18BE1], RuntimeId [42,1770052]
   at Microsoft.VisualStudio.TestTools.UITest.Extension.Uia.UiaUtility.MapAndThrowException(SystemException e, IUITechnologyElement element)
   at Microsoft.VisualStudio.TestTools.UITest.Extension.Uia.UiaElement.get_AutomationId()
   at Microsoft.VisualStudio.TestTools.UITest.Extension.Uia.UiaElement.HasValidAutomationId()
   at Microsoft.VisualStudio.TestTools.UITest.Extension.Uia.UiaElement.get_FriendlyName()
   at Microsoft.VisualStudio.TestTools.UITest.Common.UIMap.UIMapUtil.FillPropertyFromUIElement(UIObject obj, IUITechnologyElement element)
   at Microsoft.VisualStudio.TestTools.UITest.Common.UIMap.UIMapUtil.FillPropertyOfTopLevelElementFromUIElement(UIObject obj, IUITechnologyElement element)
   at Microsoft.VisualStudio.TestTools.UITest.Common.UIMap.UIMapUtil.FillTopLevelElementFromUIElement(IUITechnologyElement element, TopLevelElement obj, Boolean stripBrowserWindowTitleSuffix)
   at Microsoft.VisualStudio.TestTools.UITest.Common.UIMap.UIMapUtil.GetCompleteQueryId(UITechnologyElement pluginNode)
   at Microsoft.VisualStudio.TestTools.UITesting.UITestControl.GetQueryIdForCaching()
   at Microsoft.VisualStudio.TestTools.UITesting.UITestControl.<>c__DisplayClass6.<CacheQueryId>b__5()
   at Microsoft.VisualStudio.TestTools.UITesting.CodedUITestMethodInvoker.InvokeMethod[T](Func`1 function, UITestControl control, Boolean firePlaybackErrorEvent, Boolean logAsAction)
   at Microsoft.VisualStudio.TestTools.UITesting.UITestControl.CacheQueryId(String queryId)
   at Microsoft.VisualStudio.TestTools.UITesting.UITestControl..ctor(IUITechnologyElement element, UITestControl searchContainer, String queryIdForRefetch)
   at Microsoft.VisualStudio.TestTools.UITesting.TechnologyElementPropertyProvider.GetPropertyValue(UITestControl uiControl, String propertyName)
   at Microsoft.VisualStudio.TestTools.UITesting.UITestPropertyProvider.TryGetPropertyFromTechnologyElement(UITestControl uiControl, String propertyName, Object& value)
   at Microsoft.VisualStudio.TestTools.UITesting.PropertyProviderBase.GetPropertyValue(UITestControl uiControl, String propertyName)
   at Microsoft.VisualStudio.TestTools.UITesting.UITestPropertyProvider.GetPropertyValueWrapper(UITestControl uiControl, String propertyName)
   at Microsoft.VisualStudio.TestTools.UITesting.UITestControl.GetPropertyValuePrivate(String propertyName)

使用this提示修复了前几个错误,但是我有一些自动生成的步骤,为了重新搜索控件,我必须移动代码并且......很多不必要的讨厌的工作。

你能否提出另一种解决方案来解决这个问题?有序测试有一些技巧吗?或者对这类问题采取一些很好的清理方法?

谢谢!

1 个答案:

答案 0 :(得分:2)

这是我最近的一个项目所做的。

首先,我创建了一些CodedUI测试方法,就好像SpecFlow不存在,所以我可以将这些图层分开。然后我在C#中创建了步骤定义类,委托给我创建的编码UI测试方法。

在之前的场景钩子中,我创建了我的UIMap实例(由CodedUI测试生成器生成的类),因此每个场景都有一个新的UIMap类实例。您需要这个,因为这些类中的对象引用是缓存的。应用程序中的每个新屏幕都是CodedUI必须遍历的全新对象树。

很多时候,我的步骤定义只是直接进入CodedUI API来创建自定义搜索,我在UIMap类中使用自动生成的方法作为参考点。

详细说明我如何设置我的测试项目。

关于我的测试项目

我创建了一个新的&#34;测试&#34; Visual Studio 2010中的项目,它引用了以下库:

Microsoft (可能附带默认的测试项目模板)

  • Microsoft.VisualStudio.QualityTools.CodedUITestFramework
  • Microsoft.VisualStudio.QualityTools.UnitTestFramework
  • Microsoft.VisualStudio.TestTools.UITest.Common
  • Microsoft.VisualStudio.TestTools.UITest.Extension
  • Microsoft.VisualStudio.TestTools.UITesting
  • UIAutomationTypes

NuGet套餐

  • AutoMapper
  • AutoMapper.Net4
  • SpecFlow.Assist.Dynamic
  • TechTalk.SpecFlow

测试项目结构

这是我第一次尝试CodedUI测试。我来自Ruby on Rails背景,并在网上做了大量关于实现CodedUI测试和SpecFlow测试的阅读。它不是一个完美的设置,但它似乎对我们来说非常可维护。

Tests (Test project)
  Features/
    Bar.feature
    Foo.feature
  Regression/
    Screen1/
      TestsA.feature
      TestsB.feature
  StepDefinitions/
    CommonHooks.cs
    DataAssertionSteps.cs
    DataSteps.cs
    FormSteps.cs
    GeneralSteps.cs
    PresentationAssertionSteps.cs
    Screen1Steps.cs
    Screen2Steps.cs
  UI/
    FormMaps/
      Screen1FormMap.cs
      Screen2FormMap.cs
    UIMapLoader/
      User.cs
  UIMap.uitest (created by CodedUI test framework)

Models (C# Class Library Project)
  Entities/
    Blog.cs
    Comment.cs
    Post.cs
  Repositories/
    BlogRepository.cs
    CommentRepository.cs
    PostRepository.cs
  ViewModels/
    Screen1ViewModel.cs
    Screen2ViewModel.cs

测试/功能

此文件夹包含实施基本业务规则或验收测试的所有SpecFlow功能文件。简单屏幕有自己的功能文件,而具有更复杂业务逻辑的屏幕被分成多个功能文件。我试图保持这些功能对于商业和开发人员都很友好。

测试/回归

因为我们的Web应用程序没有在允许单元测试的庄园中构建,所以我们所有的测试都必须通过UI完成。 Tests / Regressions文件夹包含我们完整回归应用程序的所有SpecFlow功能文件。这包括真正精细的测试,例如在表单字段中键入太多字符等。这些功能并不真正意味着作为业务文档。它们只是为了防止我们因为生产问题而在凌晨3点被唤醒。为什么这些问题总是发生在凌晨3点? ...

测试/ StepDefinitions

Test / StepDefinitions文件夹包含所有SpecFlow步骤定义文件。我先将这些文件分解为常用步骤,然后再将这些文件分解为应用程序中的特定屏幕。

CommonHooks.cs - 由SpecFlow创建

[Binding]
public class CommonHooks
{
    [BeforeTestRun]
    public static void BeforeTestRun()
    {
        ...
    }

    [BeforeScenario]
    public void BeforeScenario()
    {
        User.General.OpenLauncher();
    }

    [AfterScenario]
    public void AfterScenario()
    {
        User.General.CloseBrowser();
        User.General = null;
    }
}

BeforeScenarioAfterScenario方法是我创建和/或销毁CodedUI UIMap类的实例的地方(更多关于此的更多信息)

DataAssertionSteps.cs - 断言数据显示或未显示在数据库中的步骤定义。这些都是Then ...步骤定义。

Scenario: Foo
    Then a Foo should exist

在DataAssertionSteps.cs中:

[Then(@"a Foo should exist")]
public void ThenAFooShouldExist()
{
    // query the database for a record
    // assert the record exists
}

DataSteps.cs - 使用数据为数据库设定种子或删除数据的步骤。这些是用于设置方案的所有Given ...步骤定义。

FormSteps.cs - 与表单交互的步骤定义。这些都是When I ...步骤

GeneralSteps.cs - 真正的通用步骤定义。像When I click the "Foo" link这样的事情就在这里。

PresentationAssertionSteps.cs - 断言UI正常运行的一般步骤。像Then I should see the text "Foo"这样的事情就在这里。

Screen1Steps.cs - 当我需要特定屏幕的步骤时,我为该屏幕创建了一个步骤定义文件。例如,如果我需要&#34; Blog Post&#34;屏幕,然后我创建了一个文件调用BlogPostSteps.cs,其中包含所有这些步骤定义。

测试/ UI

Tests / UI文件夹包含一系列自定义编写的C#类,我们用它们将*.feature文件中的标签文本映射到表单控件的名称。你可能不需要这一层,但我们做到了。如果表单控件名称发生更改,这样可以更轻松地重构测试项目,尤其是对于Web项目,因为HTML表单字段名称会根据我们的ascx文件中的<asp />容器而更改。

示例类:

namespace Tests.UI.FormMaps.Screen1FormMap
{
    public static IDictionary<string, string> Fields = new Dictionary<string, string>()
    {
        { "First Name", "UserControlA_PanelB_txtFirstName" },
        { ... },
        ...
    };
}

示例步骤:

When I enter "Joe" in the "First Name" textbox in the "Screen 1" form

示例步骤定义:

[When(@"I enter ""(.*)"" in the ""(.*)"" textbox in the ""(.*)"" form")]
public void WhenIEnterInTheTextboxInTheForm(string text, string labelText, string formName)
{
    if (formName == "Screen 1")
    {
        // form control name: Screen1FormMap.Fields[labelText]
    }
    ...
}

步骤定义然后使用Tests.UI.FormMaps.Screen1FormMap.Fields属性根据* .feature文件中的标签文本检索表单控件名称。

Tests.UI.FormMaps.Screen1FormMap.Fields["First Name"]

<强>测试/ UI / UIMapLoader / User.cs

此文件夹中的另一件事是UI / UIMapLoader / User.cs文件。该类是一个自定义编写的类,可以轻松访问CodedUI Test框架生成的所有UIMap类。

namespace Tests.UI.UIMapLoader
{
    public static class User
    {
        private static UIMap _general;
        public static UIMap General
        {
            get { return _general ?? (_general = new UIMap()); }
            set { _general = value; }
        }
    }
}

这样,Step Definition类可以通过以下方式轻松访问UI地图:

User.General.SomeCodedUITestRecordedMethod(...);

您在上面引用的CommonHooks.cs文件中的BeforeScenarioAfterScenario方法中看到了对此类的引用。

模型项目

这只是一个包含允许测试项目访问数据库的实体和存储库的类lib。除ViewModels目录外,这里没什么特别的。有些屏幕与数据库中的数据有着复杂的关系,因此我创建了一个ViewModel类,以允许我的SpecFlow步骤定义轻松地为数据库提供这些屏幕的数据。