基于C#UI Automation自动化测试

news2024/10/7 3:20:24

步骤

UI Automation 只适用于,标准的win32和 WPF程序

需要添加对UIAutomationClient、 UIAutomationProvider、 UIAutomationTypes的引用

代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Automation;
using System.Windows.Forms;
using System.Windows.Input;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        private Process processnotepad;
        private Process processcalc;

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //打开笔记本
            processnotepad = Process.Start(@"C:\Windows\System32\notepad.exe");
        }

        private void button2_Click(object sender, EventArgs e)
        {
            //关闭笔记本
            processnotepad.Kill();
        }

        private void button3_Click(object sender, EventArgs e)
        {
            //AutomationElement表示 UI 自动化树中的一个 UI 自动化元素,并包含由 UI 自动化客户端应用程序用作标识符的值。
            //获取当前桌面的根 AutomationElement。
            AutomationElement desktop = AutomationElement.RootElement;
            //StringBuilder不在内存中创建新对象,而是动态扩展内存以容纳修改后的字符串。
            StringBuilder sb = new StringBuilder();
            //TreeScope(枚举)包含指定 UI 自动化目录树内元素的范围的值。具体参考请点击以下链接进行查看
            //TreeScope官方链接:https://learn.microsoft.com/zh-cn/dotnet/api/system.windows.automation.treescope?view=windowsdesktop-7.0
            AutomationElementCollection topWindows = desktop.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "ApplicationFrameWindow"));//查找计算器
            for (int i = 0; i < topWindows.Count; i++)
            {
                AutomationElement topWindow = topWindows[i];
                sb.AppendLine("Name:" + topWindow.Current.Name + ";ClassName=" + topWindow.Current.ClassName);
            }
            MessageBox.Show(sb.ToString());
        }

        private void button4_Click(object sender, EventArgs e)
        {
            AutomationElement desktop = AutomationElement.RootElement;
            var calcFrame1 = desktop.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "ApplicationFrameWindow"));
            AutomationElementCollection btn2 = calcFrame1.FindAll(TreeScope.Descendants, new PropertyCondition(AutomationElement.AutomationIdProperty, "num9Button"));
            AutomationElement btn = btn2[0];
            MessageBox.Show(btn.Current.Name);
        }

        private void button5_Click(object sender, EventArgs e)
        {
            AutomationElement desktop = AutomationElement.RootElement;
            var calcFrame1 = desktop.FindFirst(TreeScope.Children,
                new PropertyCondition(AutomationElement.ClassNameProperty, "ApplicationFrameWindow"));

            Condition conditionBtn6 = new AndCondition(
                new PropertyCondition(AutomationElement.ClassNameProperty, "Button"),
                new PropertyCondition(AutomationElement.NameProperty, "六")
                );
            var btn6 = calcFrame1.FindFirst(TreeScope.Descendants, conditionBtn6);
            //InvokePattern 表示用于启动或执行单个明确操作的控件,并且这些控件在激活时不保持其状态。
            //InvokePattern.Pattern 标识 InvokePattern 控件模式。
            //InvokePattern官方链接 https://learn.microsoft.com/zh-cn/dotnet/api/system.windows.automation.invokepattern?view=windowsdesktop-7.0
            InvokePattern button6Invoke = (InvokePattern)btn6.GetCurrentPattern(InvokePattern.Pattern);
            //Invoke() 发送请求以激活控件并启动其单一、明确的操作。
            button6Invoke.Invoke();

            

            Condition conditionBtnPlus = new AndCondition(
           new PropertyCondition(AutomationElement.ClassNameProperty, "Button"),
           new PropertyCondition(AutomationElement.NameProperty, "加")
           );
            var btnPlus = calcFrame1.FindFirst(TreeScope.Descendants, conditionBtnPlus);
            InvokePattern buttonPlusInvoke = (InvokePattern)btnPlus.GetCurrentPattern(InvokePattern.Pattern);
            buttonPlusInvoke.Invoke();
        }
        private static void InvokeButton(AutomationElement e)
        {
            InvokePattern Invoke = (InvokePattern)e.GetCurrentPattern(InvokePattern.Pattern);
            Invoke.Invoke();
        }
        private static void ClickCalculatorButton(AutomationElement calcFrame1, String name)
        {
            Condition conditionBtn = new AndCondition(
               new PropertyCondition(AutomationElement.ClassNameProperty, "Button"),
               new PropertyCondition(AutomationElement.NameProperty, name)
               );
            var btn = calcFrame1.FindFirst(TreeScope.Descendants, conditionBtn);
            // MessageBox.Show(btn.Current.Name);
            if (btn == null)
            {
                throw new Exception("找不到此" + name + "的按钮");
            }
            InvokeButton(btn);
        }

        private void button6_Click(object sender, EventArgs e)
        {
            AutomationElement desktop = AutomationElement.RootElement;
            var calcFrame1 = desktop.FindFirst(TreeScope.Children,
                new PropertyCondition(AutomationElement.ClassNameProperty, "ApplicationFrameWindow"));
            ClickCalculatorButton(calcFrame1, "三");
            ClickCalculatorButton(calcFrame1, "乘以");
            ClickCalculatorButton(calcFrame1, "五");
            ClickCalculatorButton(calcFrame1, "五");
            ClickCalculatorButton(calcFrame1, "等于");
        }

        [DllImport("user32.dll")]
        public static extern void SetCursorPos(int x, int y);

        [DllImport("user32.dll")]
        public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);


        private void button7_Click(object sender, EventArgs e)
        {
            AutomationElement desktop = AutomationElement.RootElement;
            var calcFrame1 = desktop.FindFirst(TreeScope.Children,
                new PropertyCondition(AutomationElement.ClassNameProperty, "ApplicationFrameWindow"));

            Condition conditionBtn6 = new AndCondition(
                new PropertyCondition(AutomationElement.ClassNameProperty, "Button"),
                new PropertyCondition(AutomationElement.NameProperty, "六")
                );
            var btn6 = calcFrame1.FindFirst(TreeScope.Descendants, conditionBtn6);

            SetCursorPos((int)btn6.GetClickablePoint().X, (int)btn6.GetClickablePoint().Y);
            //mouse_event(0x0002 | 0x0004, 0, 0, 0, 0);
            mouse_event(0x0002, 0, 0, 0, 0);  // 模拟鼠标左键按下
            mouse_event(0x0004, 0, 0, 0, 0);  // 模拟鼠标左键弹起

        }



        private void button8_Click(object sender, EventArgs e)
        {
            AutomationElement desktop = AutomationElement.RootElement;
            var calcFrame1 = desktop.FindFirst(TreeScope.Children,
                new PropertyCondition(AutomationElement.ClassNameProperty, "Notepad"));

            Condition conditionEdit = new AndCondition( 
                new PropertyCondition(AutomationElement.ClassNameProperty, "Edit"), new PropertyCondition(AutomationElement.NameProperty, "文本编辑器"));
            AutomationElement txtEdit = calcFrame1.FindFirst(TreeScope.Descendants, conditionEdit);
            txtEdit.SetFocus();
            SendKeys.Send("追加123456789");
        }

        private const int WM_SETTEXT = 0x000C;

        [DllImport("user32.dll")]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("User32.dll")]
        private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindows);

        [DllImport("User32.dll")]
        private static extern Int32 SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, StringBuilder lParam);

        private void button9_Click(object sender, EventArgs e)
        {
            AutomationElement desktop = AutomationElement.RootElement;
            var calcFrame1 = desktop.FindFirst(TreeScope.Children,
                new PropertyCondition(AutomationElement.ClassNameProperty, "Notepad"));

            Condition conditionEdit = new AndCondition(
                new PropertyCondition(AutomationElement.ClassNameProperty, "Edit"), new PropertyCondition(AutomationElement.NameProperty, "文本编辑器"));
            AutomationElement txtEdit = calcFrame1.FindFirst(TreeScope.Descendants, conditionEdit);
            //.NET提供了一个结构体System.IntPtr专门用来代表句柄或指针。
            //句柄是对象的标识符,当调用这些API创建对象时,它们并不直接返回指向对象的指针,
            //而是会返回一个32位或64位的整数值,这个在进程或系统范围内唯一的整数值就是句柄(Handle),
            //随后程序再次访问对象,或者删除对象,都将句柄作为Windows API的参数来间接对这些对象进行操作。
            //句柄是一个结构体,简单的来说,它是指针的一个封装,是C#中指针的替代者
            //句柄链接:https://blog.csdn.net/sinat_40003796/article/details/127244155
            IntPtr hWnd = FindWindow("Notepad", null);
            if (!hWnd.Equals(IntPtr.Zero))
            {
                IntPtr edithWnd = FindWindowEx(hWnd, IntPtr.Zero, "Edit", null);
                if (!edithWnd.Equals(IntPtr.Zero))
                {
                    SendMessage(edithWnd, WM_SETTEXT, IntPtr.Zero, new StringBuilder("重写123456789"));
                }
            }
            else
            {
            }

        }

        private void button10_Click(object sender, EventArgs e)
        {
            //点击后有列表的按钮不要当成点击事件
            AutomationElement desktop = AutomationElement.RootElement;
            var calcFrame1 = desktop.FindFirst(TreeScope.Children,
                new PropertyCondition(AutomationElement.ClassNameProperty, "Notepad"));
            Condition myCondition2 = new PropertyCondition(AutomationElement.NameProperty, "编辑(E)");
            AutomationElement w2 = calcFrame1.FindFirst(TreeScope.Descendants, myCondition2);
            ExpandCollapsePattern ecp = (ExpandCollapsePattern)w2.GetCurrentPattern(ExpandCollapsePattern.Pattern);
            ecp.Expand();
        }

        private AutomationElement autoElementGet1(AutomationElement e, string s)
        {
            Condition myCondition1 = new PropertyCondition(AutomationElement.AutomationIdProperty, s);
            Condition myCondition2 = new PropertyCondition(AutomationElement.NameProperty, s);
            Condition myCondition3 = new PropertyCondition(AutomationElement.AcceleratorKeyProperty, s);
            Condition myCondition4 = new PropertyCondition(AutomationElement.ClassNameProperty, s);
            Condition myCondition5 = new PropertyCondition(AutomationElement.AccessKeyProperty, s);
            Condition myCondition6 = new PropertyCondition(AutomationElement.LocalizedControlTypeProperty, s);
            Condition myCondition = new OrCondition(myCondition1, myCondition2, myCondition3, myCondition4, myCondition5,
                myCondition6);
            AutomationElementCollection myCollection = e.FindAll(TreeScope.Descendants, myCondition);
            return myCollection[0];
        }
        private void button11_Click(object sender, EventArgs e)
        {
            //随机元素获取
            AutomationElement desktop = AutomationElement.RootElement;
            var calcFrame1 = desktop.FindFirst(TreeScope.Children,
                new PropertyCondition(AutomationElement.ClassNameProperty, "Notepad"));
            AutomationElement filename = autoElementGet1(calcFrame1, "文件(F)");
            MessageBox.Show("Name:" + filename.Current.Name + ";ClassName=" + filename.Current.ClassName);
        }

        private void button12_Click(object sender, EventArgs e)
        {
            //遍历子控件
            AutomationElement desktop = AutomationElement.RootElement;
            var calcFrame1 = desktop.FindFirst(TreeScope.Children,
                new PropertyCondition(AutomationElement.ClassNameProperty, "Notepad"));
            Condition myCondition1 = new PropertyCondition(AutomationElement.AutomationIdProperty, "MenuBar");
            AutomationElement MenuBar = calcFrame1.FindFirst(TreeScope.Descendants, myCondition1);
            AutomationElementCollection MenuBarChildAll = MenuBar.FindAll(TreeScope.Children, Condition.TrueCondition);
            for (int i = 0; i < MenuBarChildAll.Count; i++)
            {
                AutomationElement MenuBarChild = MenuBarChildAll[i];
                MessageBox.Show("Name:" + MenuBarChild.Current.Name + ";ClassName=" + MenuBarChild.Current.ClassName + ";ControlType=" + MenuBarChild.Current.ControlType);
            }


        }

        private void button13_Click(object sender, EventArgs e)
        {
            processcalc = Process.Start(@"C:\Windows\System32\calc.exe");
        }

        private void button14_Click(object sender, EventArgs e)
        {
            processcalc.Kill();
        }

        private void button15_Click(object sender, EventArgs e)
        {
            //点击后有列表的按钮不要当成点击事件
            AutomationElement desktop = AutomationElement.RootElement;
            var calcFrame1 = desktop.FindFirst(TreeScope.Children,
                new PropertyCondition(AutomationElement.ClassNameProperty, "Notepad"));
            Condition myCondition1 = new PropertyCondition(AutomationElement.NameProperty, "文件(F)");
            AutomationElement w1 = calcFrame1.FindFirst(TreeScope.Descendants, myCondition1);
            ExpandCollapsePattern ecp = (ExpandCollapsePattern)w1.GetCurrentPattern(ExpandCollapsePattern.Pattern);
            ecp.Expand();
            Condition myCondition2 = new PropertyCondition(AutomationElement.NameProperty, "退出(X)");
            AutomationElementCollection myCollection = w1.FindAll(TreeScope.Descendants, myCondition2);
            AutomationElement w2 = myCollection[0];
            InvokePattern ipn = (InvokePattern)w2.GetCurrentPattern(InvokePattern.Pattern);
            ipn.Invoke();
            Thread.Sleep(500);
            AutomationElement savefile = calcFrame1.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "保存(S)"));
            if (savefile != null)
            {
                InvokePattern savefilebutton = (InvokePattern)savefile.GetCurrentPattern(InvokePattern.Pattern);
                savefilebutton.Invoke();
                Thread.Sleep(500);
                AutomationElement Saveasform = calcFrame1.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "另存为"));
                AutomationElement edit1 = Saveasform.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.AutomationIdProperty, "1001"));
                ValuePattern vp = (ValuePattern)edit1.GetCurrentPattern(ValuePattern.Pattern);
                vp.SetValue("aaa.txt");
                AutomationElement savefilepath = Saveasform.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "保存(S)"));
                InvokePattern savefilepathbutton = (InvokePattern)savefilepath.GetCurrentPattern(InvokePattern.Pattern);
                savefilepathbutton.Invoke();
                Thread.Sleep(500);
                AutomationElement yesSaveasform = Saveasform.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "确认另存为"));
                AutomationElement issavefilepath = Saveasform.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "是(Y)"));
                if (issavefilepath != null) {
                    InvokePattern issavefilepathbutton = (InvokePattern)issavefilepath.GetCurrentPattern(InvokePattern.Pattern);
                    issavefilepathbutton.Invoke();
                }
            }
            

        }
    }
}

各按钮的功能展示

打开记事本

关闭记事本

获取计算器窗体

修改对应代码,每个按钮点击事件下的的该属性都需要进行修改

 结果

获取控件属性

 结果

点击按钮

完成计算器计算

 鼠标点击按钮

功能是让鼠标去点击,实现点击按钮的功能

 追加记事本内容

原始

运行

 重写记事本内容

展开按钮列表

随机获取元素方法

遍历记事本菜单栏

打开计算器

控件关闭计算器

 保存记事本

工程示例

https://download.csdn.net/download/qq_39397927/88215681

参考

https://www.cnblogs.com/baihuitestsoftware/articles/9047705.html

UI自动化 --- 微软UI Automation_dotNET跨平台的博客-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/878555.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

arcgis数据采集与拓扑检查

1、已准备好一张配准好的浙江省行政区划图&#xff0c;如下&#xff1a; 2、现在需要绘制湖州市县级行政区划。需要右击文件夹新建文件地理数据库&#xff0c;如下&#xff1a; 其余步骤均默认即可。 创建好县级要素数据集后&#xff0c;再新建要素类&#xff0c;命名为县。 为…

Axure中文环境配置教程,让原型设计和乱码说再见!

很多产品新人刚接触原型设计时,首选的工具通常都是Axure。我们可以在官网或者其他途径下载Axure的安装包,但安装完成后会发现,这个原型工具只提供30天的试用期。如果想继续使用,就需要输入账号和密钥进行正式授权。当安装授权工作完成后,还需要进行一项重要的设置,那就是对Axur…

Airbnb开源数据可视化工具Visx

一、什么是visx visx 是用于 React 的富有表现力的底层可视化组件集合,结合了 d3 的强大功能来生成可视化,以及 React 更新 DOM 的诸多优势。 在 Airbnb 内部,visx 的目标是统一整个公司的可视化堆栈,在此过程中,创建了 visx 项目,从而有效的将 D3 的强大功能与 React …

Server - 文字转语音 (Text to Speech) 的在线服务 TTSMaker

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132287193 TTSMaker 是一款免费的文本转语音工具&#xff0c;提供语音合成服务&#xff0c;支持多种语言&#xff0c;包括英语、法语、德语、西班…

七、Everything_本地文件搜索神器

1、Everything简介 "Everything"是Windows上一款搜索引擎&#xff0c;它能够基于文件名快速定文件和文件夹位置。不像 Windows 内置搜索&#xff0c;"Everything" 默认显示电脑上每个文件和文件夹 (就如其名 "Everything")。在搜索框输入的关键词…

[国产MCU]-BL602开发实例-LCD1602 I2C驱动

LCD1602 I2C驱动 文章目录 LCD1602 I2C驱动1、LCD1602/LCD2004介绍2、硬件准备3、驱动实现本文将详细介绍如何在K210中驱动LCD1602/LCD2004 I2C显示屏。 1、LCD1602/LCD2004介绍 LCD1602液晶显示器是广泛使用的一种字符型液晶显示模块。它是由字符型液晶显示屏(LCD)、控制驱…

Install And Understand APISIX(Master the knowledge of APISIX)

Master the knowledge of APISIX Install And Understand APISIX 环境准备 接口服务&#xff1a;gpt 接口服务&#xff08;使用 spring boot 编写的 Chat GPT 接口服务&#xff09; 调用接口示例&#xff1a; 虚拟机软件&#xff1a;VMware Workstation Pro 17 Linux 镜像&…

8.14 作业 ARM

.text .globl _gcd_gcd:mov r0,#9mov r1,#15cmp r0,r1 比较r0和r1寄存器中的值beq stopsubhi r0,r0,r1subcc r1,r1,r0stop:b stop .end用for循环实现1~100之间和&#xff1a; .text .globl _start_start:mov r0,#0 总和mov r1,#1 从1开始mov r2,#100 到100结束bl add_loopa…

docker发展历史

docker 一、docker发展历史很久以前2013年2014年2015年2016年2017年2018年2019年及未来 二、 docker概述定义&#xff1a;docker底层运行原理:docker简述核心概念容器特点Docker与虚拟机的区别: 三、容器在内核中支持两种重要技术四、namespace的六项隔离五、虚拟化产品有哪些1…

SSH隧道搭建简单使用;本地电脑局域网内网穿透外网访问

参考&#xff1a; https://www.zsythink.net/archives/2450 https://luckyfuture.top/ssh-tunnel#SSH%E9%9A%A7%E9%81%93 https://zhuanlan.zhihu.com/p/561589204?utm_id0 1、 SSH隧道&#xff08;搭建SSH隧道绕过防火墙&#xff09;&#xff1a; ssh命令除了登陆外还有代理…

判断自己网络所在的NAT类型

文章目录 各NAT类型介绍软件准备流程 各NAT类型介绍 NAT0: OpenInternet&#xff0c;没有经过NAT地址转换&#xff0c;公网IP NAT1: Full Cone NAT&#xff0c;动态家宽可以达到最优的状态&#xff0c;外网设备可以主动发信息给NAT1网络内的设备。 NAT2: Address-Restricted C…

什么是低质量无露脸直播内容?

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 无人直播带货那么火&#xff0c;很多人都在做无人直播或者半无人直播的带货&#xff0c;但很多人都是从培训者的只言片语中了解的&#xff0c;少有人看官方的内容。而今天详细规范来了。新手朋友一…

盛元广通食品药品检验检测实验室LIMS系统

随着食品与制药行业法规标准的日益提高和国家两化融合的不断推进&#xff0c;为保障检验工作的客观、公正及科学性&#xff0c;确保制药企业对于生产、实验室、物流、管理的信息化和智能化需求越来越明确&#xff0c;为确保新品可及时得到科学准确的检测检验结果&#xff0c;盛…

EthGlobal 巴黎站 Chainlink 获奖项目介绍

在 Web3 中&#xff0c;每一周都至关重要。项目的发布、版本的发布以及协议的更新以惊人的速度推出。开发者必须保持学习&#xff0c;随时了解最新的工具&#xff0c;并将所有他们所学的东西&#xff08;无论是旧的还是新的&#xff09;联系起来&#xff0c;以构建推动 Web3 技…

jQuery-表单验证

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>表单验证</title></head><body&g…

记录每日LeetCode 617.合并二叉树 Java实现

题目描述&#xff1a; 给你两棵二叉树&#xff1a; root1 和 root2 。 想象一下&#xff0c;当你将其中一棵覆盖到另一棵之上时&#xff0c;两棵树上的一些节点将会重叠&#xff08;而另一些不会&#xff09;。你需要将这两棵树合并成一棵新二叉树。合并的规则是&#xff1a;…

【高级程序设计语言C++】哈希桶

1. 哈希桶概念2. 哈希桶的基础模型3. 哈希桶的插入4. 哈希桶的删除5. 哈希桶的查找 1. 哈希桶概念 在C中&#xff0c;哈希桶是一种用于实现哈希表的数据结构。哈希表是一种高效的数据结构&#xff0c;用于存储键值对&#xff0c;并支持快速的插入、查找和删除操作。 哈希桶的…

ARM02汇编指令

文章目录 一、keil软件介绍1.1 创建工程1.2 解析start.s文件(重点)1.3 乱码解决1.4 更换背景颜色1.5 C语言内存分布1.6 解析map.lds文件(重点)1.7 常见错误信息1.8 仿真 二、汇编三种符号2.1 汇编指令2.2 伪指令2.3 伪操作 三、汇编指令格式3.1 格式3.2 注意事项 四、数据操作指…

如何看懂统一社会信用代码?

在查看企业信息的时候&#xff0c;我们通常第一时间查看的就是该企业的照面信息&#xff1a;企业名称&#xff0c;企业信用代码&#xff0c;企业法人等等。 其中统一社会信用代码就是给各个企业组织编号&#xff0c;是便于统一识别管理的一串代码&#xff0c;类似我们的身份证…