Mario洁 发表于 2018-4-20 15:11:51

初学Coded UI小结

Coded UI是自动化的功能测试,区别于探索性测试和压力测试。
Coded UI可以通过已有的Action recording来生成代码,也可以使用CodedUI Test Builder来生成代码。
在Coded UI中主要完成“跑流程”和“数据验证”。
Coded UI test可以接受多组数据并自动迭代。

完成这件事的testing framework目前还没有深入学习。先看一些表层的东西。

在Visual Studio 2010中新建一个Coded UI test,会自动生成以下代码:
CodedUITest1类。在该类中包含了一个具有TestMethodAttribute的方法CodedUITestMethod1(),执行测试
时testing framework会调用该方法。在CodedUITest1类中两个属性,一个是UIMap,一个是TestContext。
其中UIMap包含了测试中控件映射的信息。TestContext包含了测试使用的数据等信息。
UIMap类。该类是CodedUITest1类的属性UIMap的类型。在这个类中定义了很多方法,属性。
(1)为测试中的每个Action和Assertion都生成了一个方法。CodedUITest1类中的CodedUITestMethod1方
法调用UIMap类中的这些方法来完成测试。

(2)对于涉及到的每一个最外层的UI元素,都生成了一个属性。内层的UI元素包含在了外层的UI元素中。

(3)对于每个Action和Assertion需要用到的一组参数,都生成了一个属性。

其他类。主要分两种,这两种类都是为UIMap类服务的。
(1)对于涉及到的每一个UI元素,只要不是最内层的元素,都生成了一个类。这些类的构造函数中设定
“搜索条件”,在测试运行的时候,依据“搜索条件”找到相应的窗口或者控件等元素。这些类具有属性,是
被包容在其中的内层UI元素。对于最内层的UI元素,使用Microsoft.VisualStudio.TestTools.UITesting.WpfC
ontrols(或.HtmlControls,.WinControls)命名空间中的类型,”搜索条件“在get方法中设定。
(2)对于每个Action和Assertion需要用到的一组参数,比如要在输入控件中输入的数据或者需要在输出控
件中进行验证的数据,都生成了一个类,类名以Params或者ExpectedValues结尾。

举例:一个简单的WPF程序,有两个文本框接受输入(两个加数),有一个按钮,点击按钮,则在第三个
文本框中显示和数。
现在对其建立一个Coded UI测试。则自动生成以下的类:

CodedUITest1类
CodedUITestMethod1方法
UIMap属性
TestContext属性

UIMap类
AddNumbers方法
AssertTotal方法
AddNumberParams属性
AssertTotalExceptedValues属性
UIMainWindowWindow属性

AddNumbersParams类
AssertTotalExpectedValues类
UIMainWindowWindow类(该类包含以下属性:UIInput1TextBoxEdit,UIInput2TextBoxEdit,UIAddButton,
UIResultText(注:在录制的过程中,自动生成的名称可能不是UIResultText,而是UIItem3Text,可以手动
修改为更有含义的名称))

进行测试的前期工作和后期工作,比如打开应用程序和关闭应用程序,可以在单独的方法中完成。这只需要
利用两个 attribute 。在 CodedUITest1 类中,添加具有TestInitializeAttribute的方法MyTestInitialize,以及具
有TestCleanupAttribute的方法MyTestCleanup。testing framework运行每项测试之前使用 TestInitialize 运行
代码,运行每项测试之后使用 TestCleanup 运行代码。

举例:
在上述例子中,在自动生成的代码中取消”附加测试特性“代码块的注释(CodedUITest1类中CodedUITestM
ethod1方法后面,Visual Studio 2010会自动生成 MyTestInitialize 和 MyTestCleanup 方法,但是默认是被注
释掉的)。

在 MyTestInitialize方法中使用Coded UI Test Builder生成打开应用程序的代码。即在UIMap类中生成OpenA
pp方法,并在CodedUITest1类的 MyTestInitialize 方法中调用 UIMap.OpenApp 方法。

此时,在UIMap.Designer.cs文件中,自动生成了以下代码:
1.UIMap类的OpenApp方法
2.UIMap类的OpenAppParams属性
3.OpenAppParams类(该类以包含”文件路径“的string为字段)

类似地,在 MyTestCleanup 方法中使用Coded UI Test Builder生成关闭应用程序的代码。

此时,在UIMap.Designer.cs文件中,自动生成了以下代码:
1.UIMap类的CloseApp方法
2.由于关闭应用程序是通过点击右上角的关闭按钮,并不需要参数,所以不需要也没有生成CloseAppParam
s,而是将关闭按钮加入到UIMap中。具体如下:
(1)生成了一个UIMainWindowTitleBar类,该类具有属性UICloseButton。但是该titlebar元素并不是最外层的
,所以没有在UIMap类中添加一个UIMainWindowTitleBar类的属性。
(2)在UIMainWindowWindow类中添加了一个UIMainWindowTitleBar类型的属性(属性与类型同名)。在
CloseApp方法中通过UIMainWindowWindow.UIMainWindowTitleBar.UICloseButton 来对关闭按钮进行操作。
可见,在UIMap类中,只需要包含最外层的UI元素作为属性。

为了对多组数据进行测试。可以为CodedUITestMethod1方法附加DataSourceAttribute。这个attribute把一个
数据表绑定到测试方法中。数据源可以是.csv文件。然后在CodedUITestMethod1中添加一些代码,在调用
UIMap.AddNumbers之前,先对AddNumbersParams进行赋值,即指定数据表中的某一列。同样,对Assert
TotalExceptedValues进行赋值。

举例:
[DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", "D:\\DataForPractice\\data.csv", "data#
csv", DataAccessMethod.Sequential),
    TestMethod]
    public void CodedUITestMethod1()
    {
      this.UIMap.AddNumbersParams.UIInput1TextBoxEditText = TestContext.DataRow["Input1"].ToString();
      this.UIMap.AddNumbersParams.UIInput2TextBoxEditText = TestContext.DataRow["Input2"].ToString();
      this.UIMap.AddNumbers();
      this.UIMap.AssertTotalExpectedValues.UIResultTextDisplayText = TestContext.DataRow["Output"].To
String();
      this.UIMap.AssertTotal();
    }

在一个类中可以有好几个测试。
在CodedUITest1类中可以添加CodedUITestMethod2方法,为其附加TestMethodAttribute 即可。testing fram
ework会以每一个具有TestMethodAttribute的方法独立进行测试。方法执行的顺序会是:
MyTestInitialize - CodedUITestMethod1 - MyTestCleanup (迭代n1次)
MyTestInitialize - CodedUITestMethod2 - MyTestCleanup (迭代n2次)

至于 CodedUITestMethodA和 CodedUITestMethodB哪个先哪个后,如果是在菜单中选执行解决方案中的
所有测试,不是按照方法在代码中的顺序执行。如果是在测试视图中选中测试方法再执行,那么是按照在
测试视图中的顺序。

自动生成的代码能完成简单的“跑流程”和“验证数据“。但是有时候自动生成的代码不能满足复杂一些的情况,
或者是被测试的程序发生了一些改变。我们依然利用自动生成的代码,但是对其进行一些改变。修改代码
主要在两个地方。
1.测试中的Action和Assertion是与UIMap类的方法一一对应的。所以我们主要工作就是修改UIMap类的方法。
不能直接在UIMap.Designer.cs文件中修改,而要把自动生成的代码移动到UIMap.cs文件中来修改。
2.在CodedUITest1.cs中修改CodedUITestMethod。前者是修改小步骤,后者是修改大步骤。

可能遇到的情况包括以下一些:
1.在映射中添加控件
凡是测试中涉及到的UI元素全部记录在UIMap.uitest中,这是一个XML文件。而生成测试的记录中没有涉及
到UI元素则不会自动添加到UIMap.uitest中。有时候,我们需要把这些UI元素加到其中,可以使用Coded U
I Test Bulider来完成。

UIMap.uitest中的ID -- 和UIMap.Designer.cs中类的属性是同样的名字。TopLevelWindow的ID和UIMap类的
属性同名,而子代的ID则和相应父窗口对应的类的属性是同名的。

搜索条件:
ControlType -- 对应控件的类型
AutomationId -- 对应到控件的Name属性。应用程序的控件的Name是具有唯一性的,由ControlType和Aut
omationId就能准确地搜索到控件。

2.修改属性的搜索条件
实际的UI元素和UIMap.uitest中的记录一一对应,而UIMap.uitest中的记录和UIMap.Designer.cs中类及其属
性是一一对应的。当被测试的应用程序中某个控件的Name属性发生了改变(而不是控件显示的内容发生了
改变),相当于有了一个新的控件,我们首先把这个控件加入到UIMap.uitest中。此时有两种办法来保证维
护原来的代码:
(1)在UIMap的构造函数中(也可以在别的地方)修改 UIXXControl 的”搜索条件“。
this.UIMainWindowWindow.UIXXControl.SearchProperties =
"newControl";
(2)相当于有了一个新的控件,我们首先把这个控件加入到UIMap.uitest中,然后修改原来的RecordedM
ethod中的 UIXXControl (旧)为 UIXXControl(新)
public void ModifiedSimpleAppTest()
      {
      #region Variable Declarations
      WpfButton uIXXButton = this.UIMainWindowWindow.UINewXXButton; //
      #endregion
      ...
      }
这种方法并不好,它依然保留了原先的控件的记录,但原先的控件已经不存在了。

3.等待控件事件
使用UITestControl.WaitForControlXXX() 方法。如果该控件没有出现在测试记录中,则需要先用Coded UI
Test Builder记录下这个控件。

4.使用多个UIMap
每个UIMapX单独录,然后在CodedUITest类中添加属性,并调用UIMapX类的方法。



Microsoft.VisualStudio.TestTools.UITesting 命名空间

UITestControl类
这个类有WaitForControlXXX()方法
Playback类,静态类
这个类有Wait()方法,有PlaybackSettings属性
Mouse类
这个类有Hover方法。在记录鼠标悬停的时候按Ctrl+Shift+R键。

Microsoft.VisualStudio.TestTools.UITesting.WinControls 命名空间
针对Windows UI
Microsoft.VisualStudio.TestTools.UITesting.HtmlControls 命名空间
针对Web page UI
Microsoft.VisualStudio.TestTools.UITesting.WpfControls 命名空间
针对WPF UI

配置
<drive letter:>\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\CodedUITestBuilder.exe
.config
修改后无法直接保存到原目录。可以先把文件移动到桌面,编辑完了之后再移回去。


梦想家 发表于 2018-5-9 13:46:48

:victory:
页: [1]
查看完整版本: 初学Coded UI小结