CodeUI Test

简要:

CodeUI Test 是一个集成在VS2010和更高的版本上的一个公共的自动化测试API,由于它不是.NetFrameWork的一个部分,而是作为VS的一个公共组件,所以对于VS版本的依赖很大,只有在2010的Premiun和Ultimate已经更高的版本中才可以使用,对于这两个版本在安装的过程中,也会出现一些问题,导致安装路径下缺少相关的一些程序集,后期也很容易出现问题。近期由于在接触CodeUI自动化测试工具开发的项目,所以对CodeUI的这一整体技术先在原理和内部实现机制上做一个学习总结。



Agenda:

1. CodeUI 基本实现框图。

2. Sample 基本演示代码。

3.CodeUI 实现代码深度分析。



1. CodeUI 基本实现框图:



2. Sample 基本演示代码:

2.0 CodeUI已经有了一套录制操作步骤生成测试代码的功能,可以将功能测试的一些动作录制并生成测试代码,但生成的往往不会是我们最满意的效果,所以我们需要修改调整,然后执行测试时,能够模拟用户的一些功能更性操作,比如登陆,点击,录入等实现自动化测试。

2.1首先我们创建一个Winform小程序,实现加法的一个简易计算的界面,采用四个操作用例去验证它的界面计算的功能,然后我们新建一个CodeUI测试项目,自动打开我们刚刚写好的winForm小程序,然后在界面录入数据,模拟用例点击的界面用户事件,在每一个操作完成后,添加断言验证预期与实际输出是否一致。

图1:创建的测试winform计算程序

2.2 新建一个CodeUI测试项目:

2.3  打开执行刚才的winForm程序,然后新增测试项目时,选择录制:

2.4 开始录制功能测试的操作,和数据录入:

在 “txt_num1” 文本框 中键入“12345”,在 “txt_num2” 文本框 中键入“45678”, 单击 “Calculate” 按钮

在 “txt_num1” 文本框 中键入“0.123”,在 “txt_num2” 文本框 中键入“12344”, 单击 “Calculate” 按钮

在 “txt_num1” 文本框 中键入“12345.123”,在 “txt_num2” 文本框 中键入“0.123”, 单击 “Calculate” 按钮

在 “txt_num1” 文本框 中键入“1233”,在 “txt_num2” 文本框 中键入“232332”,单击 “Reset” 按钮

生成代码得到的几个重要文件如下:这也是我们最后要深入理解的程序集和文件。

核心源程序:

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Windows.Input;
using System.Windows.Forms;
using System.Drawing;
using System.Diagnostics;
using Microsoft.VisualStudio.TestTools.UITesting;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VisualStudio.TestTools.UITest.Extension;
using Keyboard = Microsoft.VisualStudio.TestTools.UITesting.Keyboard;

namespace myCodedUITest
{
    /// <summary>
    /// CodedUITest1 的摘要说明
    /// </summary>
    [CodedUITest]
    public class CodedUITest1
    {
        // public resource
       private Process process;
       private const string path = @"C:\myCodeUISample.exe";
        public CodedUITest1()
        {

        }

        [TestMethod]
        public void CodedUITestMethod1()
        {
            process= new Process();
            inistallTest();
            this.UIMap.RecordedMethod1();
            closeTest();
        }

        /// <summary>
        ///
        /// </summary>
        public void closeTest() {
            process.Close();

        }
        public void inistallTest() {

            System.Diagnostics.Process.Start(path);

        }
        #region 附加测试特性

        // 编写测试时,可以使用以下附加特性: 

        ////运行每项测试之前使用 TestInitialize 运行代码
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //    // 若要为此测试生成代码,请从快捷菜单中选择“为编码的 UI 测试生成代码”,然后选择菜单项之一。
        //}

        ////运行每项测试之后使用 TestCleanup 运行代码
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //    // 若要为此测试生成代码,请从快捷菜单中选择“为编码的 UI 测试生成代码”,然后选择菜单项之一。
        //}

        #endregion

        /// <summary>
        ///获取或设置测试上下文,该上下文提供
        ///有关当前测试运行及其功能的信息。
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }
        private TestContext testContextInstance;

        public UIMap UIMap
        {
            get
            {
                if ((this.map == null))
                {
                    this.map = new UIMap();
                }

                return this.map;
            }
        }

        private UIMap map;
    }
}

myCodedUITest

// ------------------------------------------------------------------------------
//  <auto-generated>
//      此代码由编码的 UI 测试生成器生成。
//      版本: 12.0.0.0
//
//      如果重新生成代码,则更改此文件可能会导致错误的行为,
//      并将丢失这些更改。
//  </auto-generated>
// ------------------------------------------------------------------------------

namespace myCodedUITest
{
    using System;
    using System.CodeDom.Compiler;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Text.RegularExpressions;
    using System.Windows.Input;
    using Microsoft.VisualStudio.TestTools.UITest.Extension;
    using Microsoft.VisualStudio.TestTools.UITesting;
    using Microsoft.VisualStudio.TestTools.UITesting.WinControls;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Keyboard = Microsoft.VisualStudio.TestTools.UITesting.Keyboard;
    using Mouse = Microsoft.VisualStudio.TestTools.UITesting.Mouse;
    using MouseButtons = System.Windows.Forms.MouseButtons;

    [GeneratedCode("编码的 UI 测试生成器", "12.0.21005.1")]
    public partial class UIMap
    {

        /// <summary>
        /// Test The Calculate function is performance well
        /// </summary>
        public void RecordedMethod1()
        {
            #region Variable Declarations
            WinEdit uITxt_num1Edit = this.UIForm1Window.UITxt_num1Window.UITxt_num1Edit;
            WinEdit uITxt_num2Edit = this.UIForm1Window.UITxt_num2Window.UITxt_num2Edit;
            WinButton uICalculateButton = this.UIForm1Window.UICalculateWindow.UICalculateButton;
            WinEdit uITxt_sumEdit = this.UIForm1Window.UITxt_sumWindow.UITxt_sumEdit;
            WinButton uIResetButton = this.UIForm1Window.UIResetWindow.UIResetButton;
            #endregion

            // 未录制上一个鼠标操作。

            // 在 “txt_num1” 文本框 中键入“12345”
            uITxt_num1Edit.Text = this.RecordedMethod1Params.UITxt_num1EditText;

            // 在 “txt_num2” 文本框 中键入“45678”
            uITxt_num2Edit.Text = this.RecordedMethod1Params.UITxt_num2EditText;

            // 单击 “Calculate” 按钮
            Mouse.Click(uICalculateButton, new Point(19, 18));

            AssertMethod1();

            // 单击 “txt_sum” 文本框
            Mouse.Click(uITxt_sumEdit, new Point(49, 7));

            // 在 “txt_num1” 文本框 中键入“0.123”
            uITxt_num1Edit.Text = this.RecordedMethod1Params.UITxt_num1EditText1;

            // 在 “txt_num2” 文本框 中键入“12344”
            uITxt_num2Edit.Text = this.RecordedMethod1Params.UITxt_num2EditText1;

            // 单击 “Calculate” 按钮
            Mouse.Click(uICalculateButton, new Point(45, 14));

            AssertMethod1();

            // 在 “txt_num1” 文本框 中键入“12345.123”
            uITxt_num1Edit.Text = this.RecordedMethod1Params.UITxt_num1EditText2;

            // 在 “txt_num2” 文本框 中键入“0.123”
            uITxt_num2Edit.Text = this.RecordedMethod1Params.UITxt_num2EditText2;

            // 单击 “Calculate” 按钮
            Mouse.Click(uICalculateButton, new Point(46, 13));

            AssertMethod1();

            // 单击 “Reset” 按钮
            Mouse.Click(uIResetButton, new Point(64, 12));

            AssertMethod2();

            // 在 “txt_num1” 文本框 中键入“1233”
            uITxt_num1Edit.Text = this.RecordedMethod1Params.UITxt_num1EditText3;

            // 在 “txt_num2” 文本框 中键入“232332”
            uITxt_num2Edit.Text = this.RecordedMethod1Params.UITxt_num2EditText3;

            // 单击 “Reset” 按钮
            Mouse.Click(uIResetButton, new Point(50, 7));

            AssertMethod2();
        }

        /// <summary>
        /// AssertMethod1 - 使用“AssertMethod1ExpectedValues”将参数传递到此方法中。
        /// </summary>
        public void AssertMethod1()
        {
            #region Variable Declarations
            WinEdit uITxt_num1Edit = this.UIForm1Window.UITxt_num1Window.UITxt_num1Edit;
            WinEdit uITxt_num2Edit = this.UIForm1Window.UITxt_num2Window.UITxt_num2Edit;
            WinEdit uITxt_sumEdit = this.UIForm1Window.UITxt_sumWindow.UITxt_sumEdit;
            WinButton uIResetButton = this.UIForm1Window.UIResetWindow.UIResetButton;
            #endregion

            // 点击计算后断言
            Assert.AreEqual(Double.Parse(uITxt_num1Edit.Text) + Double.Parse(uITxt_num2Edit.Text), Double.Parse(uITxt_sumEdit.Text), 0);

        }

        public void AssertMethod2() {

            #region Variable Declarations
            WinEdit uITxt_num1Edit = this.UIForm1Window.UITxt_num1Window.UITxt_num1Edit;
            WinEdit uITxt_num2Edit = this.UIForm1Window.UITxt_num2Window.UITxt_num2Edit;
            WinEdit uITxt_sumEdit = this.UIForm1Window.UITxt_sumWindow.UITxt_sumEdit;
            WinButton uIResetButton = this.UIForm1Window.UIResetWindow.UIResetButton;
            #endregion

            // 确认 “Reset” 按钮 等于“Reset”的“Name”属性
            Assert.AreEqual("", uITxt_num1Edit.Text.Trim() + uITxt_num2Edit.Text.Trim() + uITxt_sumEdit.Text.Trim(), true, "Test Runed Failed");

        }

        #region Properties
        public virtual RecordedMethod1Params RecordedMethod1Params
        {
            get
            {
                if ((this.mRecordedMethod1Params == null))
                {
                    this.mRecordedMethod1Params = new RecordedMethod1Params();
                }
                return this.mRecordedMethod1Params;
            }
        }

        public virtual AssertMethod1ExpectedValues AssertMethod1ExpectedValues
        {
            get
            {
                if ((this.mAssertMethod1ExpectedValues == null))
                {
                    this.mAssertMethod1ExpectedValues = new AssertMethod1ExpectedValues();
                }
                return this.mAssertMethod1ExpectedValues;
            }
        }

        public UIForm1Window UIForm1Window
        {
            get
            {
                if ((this.mUIForm1Window == null))
                {
                    this.mUIForm1Window = new UIForm1Window();
                }
                return this.mUIForm1Window;
            }
        }
        #endregion

        #region Fields
        private RecordedMethod1Params mRecordedMethod1Params;

        private AssertMethod1ExpectedValues mAssertMethod1ExpectedValues;

        private UIForm1Window mUIForm1Window;
        #endregion
    }

    /// <summary>
    /// 要传递到“RecordedMethod1”中的参数
    /// </summary>
    [GeneratedCode("编码的 UI 测试生成器", "12.0.21005.1")]
    public class RecordedMethod1Params
    {

        #region Fields
        /// <summary>
        /// 在 “txt_num1” 文本框 中键入“12345”
        /// </summary>
        public string UITxt_num1EditText = "12345";

        /// <summary>
        /// 在 “txt_num2” 文本框 中键入“45678”
        /// </summary>
        public string UITxt_num2EditText = "45678";

        /// <summary>
        /// 在 “txt_num1” 文本框 中键入“0.123”
        /// </summary>
        public string UITxt_num1EditText1 = "0.123";

        /// <summary>
        /// 在 “txt_num2” 文本框 中键入“12344”
        /// </summary>
        public string UITxt_num2EditText1 = "12344";

        /// <summary>
        /// 在 “txt_num1” 文本框 中键入“12345.123”
        /// </summary>
        public string UITxt_num1EditText2 = "12345.123";

        /// <summary>
        /// 在 “txt_num2” 文本框 中键入“0.123”
        /// </summary>
        public string UITxt_num2EditText2 = "0.123";

        /// <summary>
        /// 在 “txt_num1” 文本框 中键入“1233”
        /// </summary>
        public string UITxt_num1EditText3 = "1233";

        /// <summary>
        /// 在 “txt_num2” 文本框 中键入“232332”
        /// </summary>
        public string UITxt_num2EditText3 = "232332";
        #endregion
    }

    /// <summary>
    /// 要传递到“AssertMethod1”中的参数
    /// </summary>
    [GeneratedCode("编码的 UI 测试生成器", "12.0.21005.1")]
    public class AssertMethod1ExpectedValues
    {

        #region Fields
        /// <summary>
        /// 确认 “txt_num1” 窗口 等于“txt_num1”的“ControlName”属性
        /// </summary>
        public string UITxt_num1WindowControlName = "txt_num1";

        /// <summary>
        /// 确认 “txt_sum” 窗口 等于“txt_sum”的“ControlName”属性
        /// </summary>
        public string UITxt_sumWindowControlName = "txt_sum";

        /// <summary>
        /// 确认 “Reset” 按钮 等于“Reset”的“Name”属性
        /// </summary>
        public string UIResetButtonName = "Reset";
        #endregion
    }

    [GeneratedCode("编码的 UI 测试生成器", "12.0.21005.1")]
    public class UIForm1Window : WinWindow
    {

        public UIForm1Window()
        {
            #region 搜索条件
            this.SearchProperties[WinWindow.PropertyNames.Name] = "Form1";
            this.SearchProperties.Add(new PropertyExpression(WinWindow.PropertyNames.ClassName, "WindowsForms10.Window", PropertyExpressionOperator.Contains));
            this.WindowTitles.Add("Form1");
            #endregion
        }

        #region Properties
        public UITxt_num1Window UITxt_num1Window
        {
            get
            {
                if ((this.mUITxt_num1Window == null))
                {
                    this.mUITxt_num1Window = new UITxt_num1Window(this);
                }
                return this.mUITxt_num1Window;
            }
        }

        public UITxt_num2Window UITxt_num2Window
        {
            get
            {
                if ((this.mUITxt_num2Window == null))
                {
                    this.mUITxt_num2Window = new UITxt_num2Window(this);
                }
                return this.mUITxt_num2Window;
            }
        }

        public UICalculateWindow UICalculateWindow
        {
            get
            {
                if ((this.mUICalculateWindow == null))
                {
                    this.mUICalculateWindow = new UICalculateWindow(this);
                }
                return this.mUICalculateWindow;
            }
        }

        public UITxt_sumWindow UITxt_sumWindow
        {
            get
            {
                if ((this.mUITxt_sumWindow == null))
                {
                    this.mUITxt_sumWindow = new UITxt_sumWindow(this);
                }
                return this.mUITxt_sumWindow;
            }
        }

        public UIResetWindow UIResetWindow
        {
            get
            {
                if ((this.mUIResetWindow == null))
                {
                    this.mUIResetWindow = new UIResetWindow(this);
                }
                return this.mUIResetWindow;
            }
        }
        #endregion

        #region Fields
        private UITxt_num1Window mUITxt_num1Window;

        private UITxt_num2Window mUITxt_num2Window;

        private UICalculateWindow mUICalculateWindow;

        private UITxt_sumWindow mUITxt_sumWindow;

        private UIResetWindow mUIResetWindow;
        #endregion
    }

    [GeneratedCode("编码的 UI 测试生成器", "12.0.21005.1")]
    public class UITxt_num1Window : WinWindow
    {

        public UITxt_num1Window(UITestControl searchLimitContainer) :
                base(searchLimitContainer)
        {
            #region 搜索条件
            this.SearchProperties[WinWindow.PropertyNames.ControlName] = "txt_num1";
            this.WindowTitles.Add("Form1");
            #endregion
        }

        #region Properties
        public WinEdit UITxt_num1Edit
        {
            get
            {
                if ((this.mUITxt_num1Edit == null))
                {
                    this.mUITxt_num1Edit = new WinEdit(this);
                    #region 搜索条件
                    this.mUITxt_num1Edit.WindowTitles.Add("Form1");
                    #endregion
                }
                return this.mUITxt_num1Edit;
            }
        }
        #endregion

        #region Fields
        private WinEdit mUITxt_num1Edit;
        #endregion
    }

    [GeneratedCode("编码的 UI 测试生成器", "12.0.21005.1")]
    public class UITxt_num2Window : WinWindow
    {

        public UITxt_num2Window(UITestControl searchLimitContainer) :
                base(searchLimitContainer)
        {
            #region 搜索条件
            this.SearchProperties[WinWindow.PropertyNames.ControlName] = "txt_num2";
            this.WindowTitles.Add("Form1");
            #endregion
        }

        #region Properties
        public WinEdit UITxt_num2Edit
        {
            get
            {
                if ((this.mUITxt_num2Edit == null))
                {
                    this.mUITxt_num2Edit = new WinEdit(this);
                    #region 搜索条件
                    this.mUITxt_num2Edit.WindowTitles.Add("Form1");
                    #endregion
                }
                return this.mUITxt_num2Edit;
            }
        }
        #endregion

        #region Fields
        private WinEdit mUITxt_num2Edit;
        #endregion
    }

    [GeneratedCode("编码的 UI 测试生成器", "12.0.21005.1")]
    public class UICalculateWindow : WinWindow
    {

        public UICalculateWindow(UITestControl searchLimitContainer) :
                base(searchLimitContainer)
        {
            #region 搜索条件
            this.SearchProperties[WinWindow.PropertyNames.ControlName] = "btn_Calculate";
            this.WindowTitles.Add("Form1");
            #endregion
        }

        #region Properties
        public WinButton UICalculateButton
        {
            get
            {
                if ((this.mUICalculateButton == null))
                {
                    this.mUICalculateButton = new WinButton(this);
                    #region 搜索条件
                    this.mUICalculateButton.SearchProperties[WinButton.PropertyNames.Name] = "Calculate";
                    this.mUICalculateButton.WindowTitles.Add("Form1");
                    #endregion
                }
                return this.mUICalculateButton;
            }
        }
        #endregion

        #region Fields
        private WinButton mUICalculateButton;
        #endregion
    }

    [GeneratedCode("编码的 UI 测试生成器", "12.0.21005.1")]
    public class UITxt_sumWindow : WinWindow
    {

        public UITxt_sumWindow(UITestControl searchLimitContainer) :
                base(searchLimitContainer)
        {
            #region 搜索条件
            this.SearchProperties[WinWindow.PropertyNames.ControlName] = "txt_sum";
            this.WindowTitles.Add("Form1");
            #endregion
        }

        #region Properties
        public WinEdit UITxt_sumEdit
        {
            get
            {
                if ((this.mUITxt_sumEdit == null))
                {
                    this.mUITxt_sumEdit = new WinEdit(this);
                    #region 搜索条件
                    this.mUITxt_sumEdit.WindowTitles.Add("Form1");
                    #endregion
                }
                return this.mUITxt_sumEdit;
            }
        }
        #endregion

        #region Fields
        private WinEdit mUITxt_sumEdit;
        #endregion
    }

    [GeneratedCode("编码的 UI 测试生成器", "12.0.21005.1")]
    public class UIResetWindow : WinWindow
    {

        public UIResetWindow(UITestControl searchLimitContainer) :
                base(searchLimitContainer)
        {
            #region 搜索条件
            this.SearchProperties[WinWindow.PropertyNames.ControlName] = "btn_Reset";
            this.WindowTitles.Add("Form1");
            #endregion
        }

        #region Properties
        public WinButton UIResetButton
        {
            get
            {
                if ((this.mUIResetButton == null))
                {
                    this.mUIResetButton = new WinButton(this);
                    #region 搜索条件
                    this.mUIResetButton.SearchProperties[WinButton.PropertyNames.Name] = "Reset";
                    this.mUIResetButton.WindowTitles.Add("Form1");
                    #endregion
                }
                return this.mUIResetButton;
            }
        }
        #endregion

        #region Fields
        private WinButton mUIResetButton;
        #endregion
    }
}

uimap.designer.cs

2.5 执行测试:

3.CodeUI 实现代码深度分析:

CodeUI Test的核心我认为其实是如何获取测试环境(程序运行环境)上的UI控件,并能够操作它的属性和方法,而且目前支持WPF,Winform……但这些都得力与开放的一些API,下面我们就来看一下。

几个重要的程序集:

Microsoft.VisualStudio.QualityTools.CodedUITestFramework.dll

Microsoft.VisualStudio.TestTools.UITesting.dll  -----提供了初始化应用程序界面控件的封装。

ps:我们本次使用的是winform程序,所以为了初始化和获取到界面控件,引入了winControls声明和操作winForm控件属性和方法。

Microsoft.VisualStudio.TestTools.UITest.Extension.dll

Microsoft.VisualStudio.TestTools.UITest.Common.dll  ---主要用户Test代码生成相关的类

今天先写到这里吧,明天再做一些更深入的代码补充。

CodeUI Test

时间: 2024-08-10 15:50:08

CodeUI Test的相关文章

(五)使用代码创建UI

1 package com.example.codeUI; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.view.Gravity; 6 import android.widget.LinearLayout; 7 import android.widget.TextView; 8 9 public class MainActivity extends Activity { 10 11 @

(六)代码编写UI

/*MainActivity中代码*/ 1 package com.example.codeUI; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.view.Gravity; 6 import android.widget.LinearLayout; 7 import android.widget.TextView; 8 9 public class MainActivity extend

javaweb代码生成器,专注于javaweb项通用目的代码生成器

该项目为javaWEB项目通用代码生成器,根据数据库表和自定义代码模板生成相应的jsp,js,java文件,生成到指定路径下,javaweb项目开发利器: 项目开源地址:https://gitee.com/okrs.cn/CodeGenerator 代码生成器:该项目为代码生成器 基于Apache Velocity的 Java模板引擎base_build文件夹为最原始代码为整理后的版本执行:com.mmk.BaseApplication.java或生成jar包:run Maven intall

Sikuli--基于像素的图像识别(JAVA)

SikuliX简介及安装 package wincalc; import org.sikuli.script.Screen; public class SikuliDemo { // Sikuli是基于PC图像识别的自动化测试工具. // 目前绝大多数GUI工具均需要依赖与程序类型进行特征识别(属性识别) // TestComplete/CodeUi/Selenium/Appium/UIautomatior/WatiR // 面对不同的程序类型,则无法有效大处理,SikuliX图像识别可以通吃

Windows Automation API和自动化测试

https://zhuanlan.zhihu.com/p/22083601\ 感谢轮子哥点赞,这会儿消息扎堆过来了,轮带逛果然不是随便说说的…… 第二篇一个简单的Windows Automation API测试用例已经更新. 之前回答了一个问题https://www.zhihu.com/question/49452639/answer/117174974?group_id=749327470490025984,本来是说那个火车票查询软件的,捎带说了一句UI自动化测试,结果评论里大家对Window