“.NET研究”VS2010测试功能之旅:编码的UI测试(3)-操作对象的识别原理

简介:   回顾   在之前的两章分别介绍了一个简单的示例, 操作动作的录制原理,通过修改UIMap.UItest文件控制操作动作代码的生成。想必大家对编码的UI测试操作动作的录制应该有一定了解了,在UI操作中,操作动作总是离不开具体的操作对象,例如点击,拖动,填写值等操作,总是要对文本框,或者按钮,窗体这些对象进行操作,不是凭空生成的。

  回顾 

  在之前的两章分别介绍了一个简单的示例, 操作动作的录制原理,通过修改UIMap.UItest文件控制操作动作代码的生成。想必大家对编码的UI测试操作动作的录制应该有一定了解了,在UI操作中,操作动作总是离不开具体的操作对象,例如点击,拖动,填写值等操作,总是要对文本框,或者按钮,窗体这些对象进行操作,不是凭空生成的。本章作为入门篇的最后一章,将会说明编码的UI测试是如何识别这些对象的,并介绍UIMap.UItest文件是如何生成对象识别代码。

  对象的识别原理

  之前我们录制的时候,录制生成器解析了我们的操作对象,并且为我们生成了对象识别代码(也就是UIMap.UItest下<Map>节点的那部分),以便我们在回放的时候,能够识别到我们要操作的是哪一个对象。

  在编码的UI测试中,对象的识别主要是同时按以下三个方面进行。

  1. 按对象类别:对象属于什么类别,例如是button还是textBox 。

  2. 按关键标识属性:能唯一识别该对象的属性 。

  3. 按层级关系:对象在其父对象中的层次 。

  下面开始进行详细介绍: 

  一、按对象类别:  

  为便于理解,以web程序为例,假设我们的识别代码中,写明让VS2010按WebButton识别一个对象,那么VS2010则会在页面源码中只找到那些html标签是<input type=“submit”>的控件,如果识别代码中描写的是按WebLink识别对象,则VS2010只在页面源码中找到那些是<a>的标签。 

  二、按关键标识属性:

  通过对象类别,已经能识别出来某一类的对象,在这个基础上,接下来就需要用关键识别属性进行精准标识了,我们需要找出能唯一识别该对象的属性,假如一个窗体如下。

  这个窗体中包含了3个button,我们想让VS2010操作到第一个Button,如何区分这些Button呢?这就要用到关键标识属性来标识唯一一个对象。

  关键标识属性分为两种----自身标识属性和辅助标识属性。 

  1、自身标识属性: 

  也就是属于对象的属性,例如,button拥有Name,Text,Enable,BackColor等属性,我们假设上面那个窗体的Button的各个属性如下。

  很明显可以发现,第一个button的Name属性和和其他的button不一样,那么可以用其作为他的关键标识属性,并且写在识别代码中,这样vs2010就可以在这些button中能唯一识别他,例如,将Name=button2写到识别代码中,就可以唯一识别第二个Button。

  假设3个button的Name一样,而BackColor不同,也可以用BackColor作为关键标识属性。

  2、辅助标识属性:

  在自动化测试中,还有一种属性叫做辅助标识属性,他并不属于对象的属性,但可以辅助标识对象。

  假设刚才那个窗体的各button属性如下:

  可以发现他们的自身属性都是一模一样的,那么怎么做才能让VS2010识别他呢?仔细观察可以发现这样一个情况。

  我们可以通过该对象是第几个对象这样的辅助属性进行标识他。

  比如如果要识别第3个Button,则需要在识别代码中设置其辅助标识属性“对象序号”为3。

  三、按层级关系:

  虽然上面确定了唯一对象,的确已经可以标识出对象了,不过实际上在识别的时候还会按层级关系查找,例如第一章提到的一个简单的窗体。

  我们用录制生成器解析他的第一个文本框Tbx_uid,在自动生成的识别代码中,他们的层级关系是这样的。

  对应到刚才的Form,层级为:

  VS2010在识别这个Textbox1的时候,会只识别属于 系统登录Window下的Tbx_uidWindow下的Tbx_uid文本框。

  (注:按照常规的理解,其实应该“系统登录窗体”和“Tbx_uid文本框”只有两个层级,也就是窗体下直接就是文本框,但是VS2010默认解析的时候,会把一个TextBox解析成两个层级,分为TextBoxWindow和TextBoxEdit,结果本来应该总共只有两级结果搞成了三级,如果仔细观察可以发现其他控件也是这样的,所以在这里纠结的朋友希望你们看到此段后能够减轻些疑惑...)

  UIMap.UItest文件控制识别代码的生成

  在第二章上部分已经提到,在UIMap.uitest文件中,对象的识别代码的生成部分是放在<Maps>节点下的,点击生成代码后,会将其真正起作用的识别代码生成到UIMap.designer.cs下,那么他们的代码究竟是怎样的呢?

以刚才那个窗体生成的代码为例,我们要识别TextBox1,如果使用录制生成器,把TextBox1填入到对象库,我们来看看他生成的识别代码(可以简略看,下面会有说明)。

 
 
< Maps >
< UIMap Id ="UIMap1" >
< TopLevelWindows >
< TopLevelWindow ControlType ="Window" Id ="UI 系统登录Window" FriendlyName ="系统登录" SpecialControlType ="None" SessionId ="199642" >
< TechnologyName > MSAA </ TechnologyName >
< WindowTitles >
< WindowTitle > 系统登录 </ WindowTitle >
</ WindowTitles >
< SearchConfigurations >
< SearchConfiguration > VisibleOnly </ SearchConfiguration >
</ SearchConfigurations >
< AndCondition Id ="SearchCondition" >
< PropertyCondition Name ="Name" & gt;系统登录</PropertyCondition >
< PropertyCondition Name ="ClassName" Operator ="Contains" > WindowsForms10.Window </ PropertyCondition >
< PropertyCondition Name ="ControlType" > Window </ PropertyCondition >上海闵行企业网站设计与制作span style="color: #000000;">
</ AndCondition >
< SupportLevel > 0 </ SupportLevel >
< Descendants >
< UIObject ControlType ="Window" Id ="UITbx_uidWindow" FriendlyName ="Tbx_uid" SpecialControlType ="None" >
< TechnologyName > MSAA </ TechnologyName >
< WindowTitles >
< WindowTitle > 系统登录 </ WindowTitle >
</ WindowTitles >
< SearchConfigurations >
< SearchConfiguration > VisibleOnly </ SearchConfiguration >
</ SearchConfigurations >
< AndCondition Id ="SearchCondition" >
<上海企业网站设计与制作span>PropertyCondition Name="ControlName">Tbx_uid</PropertyCondition>
<PropertyCondition Name="ControlType">Window</PropertyCondition>
</AndCondition>
<SupportLevel>0</SupportLevel>
<Descendants>
<UIObject ControlType="Edit" Id="UITbx_uidEdit" FriendlyName="Tbx_uid" SpecialControlType="None">
<TechnologyName>MSAA</TechnologyName>
<WindowTitles>
<WindowTitle> 系统登录</WindowTitle>
</WindowTitles>
<SearchConfigurations>
<SearchConfiguration>VisibleOnly</SearchConfiguration>
</SearchConfigurations>
<AndCondition Id="SearchCondition">
<PropertyCondition Name="Name"& gt;密码 :</PropertyCondition>
<PropertyCondition Name="ControlType">Edit</PropertyCondition>
</AndCondition>
<SupportLevel>0</SupportLevel>
<Descendants />
</UIObject>
</Descendants>
</UIObject>
</Descendants>
</TopLevelWindow>
</TopLevelWindows>
</UIMap>
</Maps>

  别看UIMap.uitest里为这些对象生成的了一大堆代码,其实对象中真正管作用的属性就ControlType,ID两个:

  ID这个属性表示调用对象在对象库中的ID,例如在第二章下部分,编写ExecuteActions的时候,描述对那个上海徐汇企业网站设计与制作对象进行操作

  ControlType这个属性用于描述按什么类别来识别对象,识别原理之一的对象类别就是用这个表示  

   而管作用的节点也就这么两个:

  <AndCondition>这个节点表示识别条件,他的子节点为<PropertyCondition>,表示具体识别条件,识别原理之二的关键标识属性就用这个表示

  <Descenda上海徐汇企业网站制作nts>这个节点用于存放这个对象的子对象,识别原理之三的层级关系就是用这个表示 。

  现在把上面自动生成的代码优化一下,把不必要的代码删除,并加上注释。然后再使用这段XML代码在录制生成器生成UIMap.designer.cs代码:

 
 
< Maps >
< UIMap Id ="UIMap1" >
< TopLevelWindows >
<!-- 表示最高级别的窗体,属性ControlType表示按类型“Window”类型识别对象,对应识别原理之一 -->
< TopLevelWindow ControlType ="Window" Id ="UI 系统登录Window" >
<!-- TechnologyName标签没有实际作用,但是删除了会报错,因此保留,之后的也是 -->
< TechnologyName > MSAA </ TechnologyName >
< AndCondition Id ="SearchCondition" >
<!-- 表示窗体的关键标识属性,识别的时候寻找Name属性为“系统登录”的窗体,对应识别原理之二 -->
< PropertyCondition Name ="Name" & gt;系统登录</PropertyCondition >
<!-- 表示窗体的关键标识属性,识别的时候寻找ClassName属性为“WindowsForms10.Window”的窗体 -->
< PropertyCondition Name ="ClassName" Operator ="Contains" > WindowsForms10.Window </ PropertyCondition >
</ AndCondition >
<!-- 表示窗体的子对象,对应识别原理之三 -->
< Descendants >
<!-- UI 对象,按类型“Window”类型识别 -->
< UIObject ControlType ="Window" Id ="UITbx_uidWindow"上海网站建设pan style="color: #0000ff;">>
< TechnologyName > MSAA </ TechnologyName >
< AndCondition Id ="SearchCondition" >
<!-- 关键标识属性,ControlName属性为“Tbx_uid”的对象 -->
< PropertyCondition Name ="ControlName" > Tbx_uid </ PropertyCondition >
</ AndCondition >
<!-- 他的子对象 -->
< Descendants >
<!-- UI 对象,按类型“Edit”(文本框)类型识别 -->
< UIObject ControlType ="Edit" Id ="UITbx_uidEdit" >
< TechnologyName > MSAA </ TechnologyName >
< AndCondition Id ="SearchCondition" >
<!-- 关键标识属性,Name属性为“密码 :” -->
< PropertyCondition Name ="Name" & gt;密码 :</PropertyCondition >
</ AndCondition >
< Descendants />
</ UIObject >
</ Descendants >
</ UIObject >
</ Descendants >
</ TopLevelWindow >
</ TopLevelWindows >
</ UIMap >
</ Maps >

  接下来使用录制生成器生成UIMap.designer.cs代码,可以看到代码如下: 

 
 
[GeneratedCode( " 编码的 UI 测试生成器 " , " 10.0.30319.1 " )]
public class UI 系统登录Window : WinWindow // 这里的继承于WinWindow,是根据刚才XML文件里的属性 ControlType="Window"生成的,表示按Window识别,对应识别原理之一
{
public UI 系统登录Window()
{
// 这里是搜索条件,也就是关键识别属性,根据XML 文件的AndCondition节点中的内容生成,对应识别原理之二
#region 搜索条件
this .SearchProperties[WinWindow.PropertyNames.Name] = " 系统登录 " ;
this .SearchProperties.Add( new PropertyExpression(WinWindow.PropertyNames.ClassName, " WindowsForms10.Window " , PropertyExpressionOperator.Contains));
#endregion
}

// 这里是他的子对象,对应于XML文件的Descendants节点,对应识别原理之三
#region Properties
public UITbx_uidWindow UITbx_uidWindow
{
get
{
if (( this .mUITbx_uidWindow == null ))
{
this .mUITbx_uidWindow = new UITbx_uidWindow( this );
}
return this .mUITbx_uidWindow;
}
}
#endregion

#region Fields
private UITbx_uidWindow mUITbx_uidWindow;
#endregion
}
[GeneratedCode(
" 编码的 UI 测试生成器 " , " 10.0.30319.1 " )]
public class UITbx_uidWindow : WinWindow // 这里的继承于WinWindow,是根据刚才XML文件里的属性ControlType="Window"生成的,表示按Window识别
{

public UITbx_uidWindow(UITestControl searchLimitContainer) :
base (searchLimitContainer)
{
// 这里是搜索条件,也就是关键识别属性,根据XML文件的AndCondition节点中的内容生成
#region 搜索条件
this .SearchProperties[WinWindow.PropertyNames.ControlName] = " Tbx_uid " ;
#endregion
}
// 这里是他的子对象,对应于XML文件的Descendants节点
#region Properties
public WinEdit UITbx_uidEdit // 这里的类型为WinEdit,是根据刚才XML文件里的属性ControlType生成的(ControlType="Edit")
{
get
{
if (( this .mUITbx_uidEdit == null ))
{
this .mUITbx_uidEdit = new WinEdit( this );
// 这里是搜索条件,也就是关键识别属性,根据XML文件的AndCondition节点中的内容生成
#region 搜索条件
this .mUITbx_uidEdit.SearchProperties[WinEdit.PropertyNames.Name] = " 密码 : " ;
#endregion
}
return this .mUITbx_uidEdit;
}
}
#endregion

#region Fields
private WinEdit mUITbx_uidEdit;
#endregion
}

总结

  在本章介绍了VS2010的对象识别原理,想必大家对这个应该有所了解了吧?

  我曾今在用UI测试做项目的时候,经常会发现这样那样的对象不能用录制生成器识别,这个时候怎么办呢?了解了对象识别原理,就可以自己改XML文件来控制对象的识别,如果有想做这方面练习的朋友,可以留下你的邮箱,我这里正在编写一个C# Winform小程序,这个程序上的所有控件都经过特殊处理,无法用录制生成器识别,只有通过自己修改XML文件来控制它的识别,如果想试试自己的身手,别忘了留下邮箱哦~~

  到这里编码的UI测试的入门篇就完结了,接下来会进入进阶篇,以实际的例子描述如何对一个项目进行测试。

  附1:VS2010编码的UI测试支持识别的对象  

平台 支持级别
Windows Internet Explorer 7.0
Windows Internet Explorer 8.0
(包括 HTML 和 AJAX)
完全支持
Windows Internet Explorer 6.0 不支持
镶边OperaSafari 不支持
Silverlight 3.0 不支持
Flash/Java 不支持
Windows 窗体 2.0 及更高版本 完全支持
注意
完全支持 NetFx 控件,但并非支持所有第三方控件。
WPF 3.5 及更高版本 完全支持
注意
完全支持 NetFx 控件,但并非支持所有第三方控件。
Windows Win32 可适用于某些已知问题,但不正式支持
MFC 可适用于某些已知问题,但不正式支持
SharePoint 部分支持
Office 客户端应用程序 不支持
Dynamics (Ax) 部分支持
SAP 不支持
Citrix/终端服务 部分支持

  注:Silverlight4 现在已支持,详情见http://www.silverlightshow.net/news/Coded-UI-testing-for-Silverlight-4-now-available-.aspx,

  园子里scottxu已有这方面研究,相关文章http://www.cnblogs.com/scottxu/archive/2011/02/28/1967112.html

[GeneratedCode("编码的 UI 测试生成器", "10.0.30319.1")]
public class UI 系统登录Window : WinWindow//这里的继承于WinWindow,是根据刚才XML文件里的属性 ControlType="Window"生成的,表示按Window识别,对应识别原理之一
 {

    public UI 系统登录Window()
    {
        //这里是搜索条件,也就是关键识别属性,根据XML 文件的AndCondition节点中的内容生成,对应识别原理之二
         #region 搜索条件
        this.SearchProperties[WinWindow.PropertyNames.Name] = " 系统登录";
        this.SearchProperties.Add(new PropertyExpression(WinWindow.PropertyNames.ClassName, "WindowsForms10.Window", PropertyExpressionOperator.Contains));
        #endregion
    }

    // 这里是他的子对象,对应于XML文件的Descendants节点,对应识别原理之三
     #region Properties
    public UITbx_uidWindow UITbx_uidWindow
    {
        get
        {
            if ((this.mUITbx_uidWindow == null))
            {
                this.mUITbx_uidWindow = new UITbx_uidWindow(this);
            }
            return this.mUITbx_uidWindow;
        }
    }
    #endregion

    #region Fields
    private UITbx_uidWindow mUITbx_uidWindow;
    #endregion
}


[GeneratedCode(" 编码的 UI 测试生成器", "10.0.30319.1")]
public class UITbx_uidWindow : WinWindow// 这里的继承于WinWindow,是根据刚才XML文件里的属性ControlType="Window"生成的,表示按Window识别
 {

    public UITbx_uidWindow(UITestControl searchLimitContainer) :
            base(searchLimitContainer)
    {
        // 这里是搜索条件,也就是关键识别属性,根据XML文件的AndCondition节点中的内容生成
         #region 搜索条件
        this.SearchProperties[WinWindow.PropertyNames.ControlName] = "Tbx_uid";
        #endregion
    }
    // 这里是他的子对象,对应于XML文件的Descendants节点
     #region Properties
    public WinEdit UITbx_uidEdit// 这里的类型为WinEdit,是根据刚才XML文件里的属性ControlType生成的(ControlType="Edit")
    {
        get
        {
            if ((this.mUITbx_uidEdit == null))
            {
                this.mUITbx_uidEdit = new WinEdit(this);
                // 这里是搜索条件,也就是关键识别属性,根据XML文件的AndCondition节点中的内容生成
                #region 搜索条件
                this.mUITbx_uidEdit.SearchProperties[WinEdit.PropertyNames.Name] = " 密码 :";
                #endregion
            }
            return this.mUITbx_uidEdit;
        }
    }
    #endregion

    #region Fields
    private WinEdit mUITbx_uidEdit;
    #endregion
}
目录
相关文章
|
XML Java 测试技术
Spring5入门到实战------17、Spring5新功能 --Nullable注解和函数式注册对象。整合JUnit5单元测试框架
这篇文章介绍了Spring5框架的三个新特性:支持@Nullable注解以明确方法返回、参数和属性值可以为空;引入函数式风格的GenericApplicationContext进行对象注册和管理;以及如何整合JUnit5进行单元测试,同时讨论了JUnit4与JUnit5的整合方法,并提出了关于配置文件加载的疑问。
Spring5入门到实战------17、Spring5新功能 --Nullable注解和函数式注册对象。整合JUnit5单元测试框架
|
存储 开发框架 JavaScript
深入探讨Flutter中动态UI构建的原理、方法以及数据驱动视图的实现技巧
【6月更文挑战第11天】Flutter是高效的跨平台移动开发框架,以其热重载、高性能渲染和丰富组件库著称。本文探讨了Flutter中动态UI构建原理与数据驱动视图的实现。动态UI基于Widget树模型,状态变化触发UI更新。状态管理是关键,Flutter提供StatefulWidget、Provider、Redux等方式。使用ListView等可滚动组件和StreamBuilder等流式组件实现数据驱动视图的自动更新。响应式布局确保UI在不同设备上的适应性。Flutter为开发者构建动态、用户友好的界面提供了强大支持。
528 2
|
XML Java Maven
在 Cucumber 测试中自动将 Cucumber 数据表映射到 Java 对象
在 Cucumber 测试中自动将 Cucumber 数据表映射到 Java 对象
508 7
|
存储 开发框架 .NET
浅析.NET6中的await原理
浅析.NET6中的await原理
345 1
|
存储 算法 Java
深入理解.NET中的托管堆及其工作原理
【8月更文挑战第31天】
382 2
|
XML JavaScript 测试技术
Web自动化测试框架(基础篇)--HTML页面元素和DOM对象
本文为Web自动化测试入门指南,介绍了HTML页面元素和DOM对象的基础知识,以及如何使用Python中的Selenium WebDriver进行元素定位、操作和等待机制,旨在帮助初学者理解Web自动化测试中的关键概念和操作技巧。
432 1
|
测试技术
详解单元测试问题之处理@Mock注解时mock对象的创建如何解决
详解单元测试问题之处理@Mock注解时mock对象的创建如何解决
462 1
|
测试技术
详解单元测试问题之@InjectMocks注入mock对象如何解决
详解单元测试问题之@InjectMocks注入mock对象如何解决
1458 1
|
Java 测试技术 数据库
Java一分钟之-Mockito:模拟对象测试
【6月更文挑战第4天】Mockito是Java单元测试中的模拟框架,用于创建和配置模拟对象以隔离测试代码。核心概念包括:模拟对象、预期行为(定义方法调用响应)、验证(检查方法调用)和捕获参数。常见问题包括过度模拟、忽略未使用的模拟调用、不恰当配置和误用Mockito注解。解决方案包括正确选择模拟对象、验证所有交互、仔细配置模拟行为及在测试类中正确使用Mockito注解。提供的代码示例展示了如何使用Mockito模拟和验证方法调用,以实现独立且准确的测试。学习和避免这些易错点可提升测试效率和代码质量。
836 0
Java一分钟之-Mockito:模拟对象测试
|
测试技术 C# 开发者
“代码守护者:详解WPF开发中的单元测试策略与实践——从选择测试框架到编写模拟对象,全方位保障你的应用程序质量”
【8月更文挑战第31天】单元测试是确保软件质量的关键实践,尤其在复杂的WPF应用中更为重要。通过为每个小模块编写独立测试用例,可以验证代码的功能正确性并在早期发现错误。本文将介绍如何在WPF项目中引入单元测试,并通过具体示例演示其实施过程。首先选择合适的测试框架如NUnit或xUnit.net,并利用Moq模拟框架隔离外部依赖。接着,通过一个简单的WPF应用程序示例,展示如何模拟`IUserRepository`接口并验证`MainViewModel`加载用户数据的正确性。这有助于确保代码质量和未来的重构与扩展。
1122 0

热门文章

最新文章