基于C#UI Automation自动化测试

步骤

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博客

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【ARM 调试】如何从 crash 信息找出问题原因

一、问题背景 粉丝在进行 ARM-A 系列软件编程时遇到以下问题&#xff0c;串口打印这段日志后就重启了&#xff0c;粉丝求助问是什么原因&#xff1f; Unhandled Exception in EL3. x30 0x0000000000b99b84 x0 0x00000000179a25b0 x1 …

Prometheus技术文档-基本使用-配置文件全解!!!!!

简介&#xff1a; Prometheus是一个开源的系统监控和告警系统&#xff0c;由Google的BorgMon监控系统发展而来。它主要用于监控和度量各种时间序列数据&#xff0c;比如系统性能、网络延迟、应用程序错误等。Prometheus通过采集监控数据并存储在时间序列数据库中&#xff0c;…

【apifox】如何写一份合格的 API 文档?

要想弄清楚如何开始写出一份合格的 API 文档&#xff0c;我们需要首先了解什么是 API&#xff0c;它的使用场景有哪些&#xff0c;应该具备什么样的能力。 什么是 API&#xff1f; 想象一下&#xff0c;当小 A 购入了一台新的电脑后&#xff0c;希望将显示画面投射至一块色准…

对比学习论文综述总结

第一阶段:百花齐放(18-19中) 有InstDisc(Instance Discrimination)、CPC、CMC代表工作。在这个阶段方法模型都还没有统一,目标函数也没有统一,代理任务也没有统一,所以说是一个百花齐放的时代 1 判别式代理任务---个体判别任务 1.1 Inst Dict---一个编码器+一个memory…

Redis_主从复制

8. 主从复制 8.1 简介 主从库采用读写分离的方式 读操作&#xff1a;主库、从库都可以处理写操作&#xff1a;首先写到主库执行&#xff0c;然后再将主库同步给从库。 实现读写分离&#xff0c;性能扩展 容灾快速恢复 8.2 主从复制步骤 创建一个目录 ,在root下创建一个m…

2009年下半年 软件设计师 上午试卷

博主介绍&#xff1a;✌全网粉丝3W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

RedisDesktopManage

RDM 简介下载安装 简介 RedisDesktopManager&#xff08;RDM&#xff09;是一个开源的跨平台图形界面工具&#xff0c;用于管理和操作 Redis 数据库。它提供了一个用户友好的界面&#xff0c;使用户能够轻松地连接、浏览、查询和修改 Redis 数据&#xff0c;而无需使用命令行界…

ubuntu部署haproxy

HAProxy是可提供高可用性、负载均衡以及基于TCP和HTTP应用的代理. 1、更新系统报 通过在终端中运行以下命令,确保所有系统包都是最新的 sudo apt updatesudo apt upgrade 2、安装Haproxy sudo apt install haproxy 设置开机自动启动haproxy服务 sudo systemctl enable h…

都说go协程性能好,这次我们来试试java协程

java 协程原理 在Java中&#xff0c;协程&#xff08;Coroutine&#xff09;是一种轻量级的线程解决方案&#xff0c;它可以在代码中实现类似于多线程的并发操作&#xff0c;但不涉及线程的创建和切换开销。 在传统的Java多线程编程模型中&#xff0c;线程的切换开销较大&…

0142 存储系统2

目录 3.存储系统 3.4外部存储器 3.5高速缓冲存储器 3.6虚拟存储器 部分习题 3.存储系统 3.4外部存储器 3.5高速缓冲存储器 3.6虚拟存储器 部分习题 1.一个磁盘转速为7200转/分&#xff0c;每个磁道有160个扇区&#xff0c;每个扇区有512字节&#xff0c;则在理想情况下&…

SQL | 使用函数处理数据

8-使用函数处理数据 8.1-函数 SQL可以用函数来处理数据。函数一般是在数据上执行的&#xff0c;为数据的转换和处理提供了方便。 8.1.1 函数带来的问题 每种DBMS都有特定的函数&#xff0c;只有很少一部分函数&#xff0c;是被所有主要的DBMS等同的支持。 虽然所有的类型的…

YOLO相关原理(文件结构、视频检测等)

超参数进化(hyperparameter evolution) 超参数进化是一种使用了genetic algorithm&#xff08;GA&#xff09;遗传算法进行超参数优化的一种方法。 YOLOv5的文件结构 images文件夹内的文件和labels中的文件存在一一对应关系 激活函数&#xff1a;非线性处理单元 activation f…

使用Python和pyodbc库将文件信息插入Access数据库

将文件信息插入 Access 数据库的博客文章示例&#xff1a; 简介&#xff1a; 在日常编程工作中&#xff0c;我们经常需要处理文件和文件夹。有时&#xff0c;我们需要遍历文件夹中的所有文件&#xff0c;并将文件的路径、类型、文件名以及修改日期和创建日期等信息保存到数据库…

Ajax 笔记(一)—— Ajax 入门

笔记目录 1. Ajax 入门1.1 Ajax 概念1.2 axios 使用1.2.1 URL1.2.2 URL 查询参数1.2.3 小案例-查询地区列表1.2.4 常用请求方法和数据提交1.2.5 错误处理 1.3 HTTP 协议1.3.1 请求报文1.3.2 响应报文 1.4 接口文档1.5 案例1.5.1 用户登录&#xff08;主要业务&#xff09;1.5.2…

会玩这 10 个 Linux 命令,一定是个有趣的 IT 男!

Linux当中有很多比较有趣的命令&#xff0c;可以动手看看&#xff0c;很简单的。 1.rev命令 一行接一行地颠倒所输入的字符串。 运行&#xff1a; $rev如输入&#xff1a;shiyanlou shiyanlou2.asciiview命令 1.先安装aview $sudo apt-get install aview2.再安装imagema…

react中使用路由起手式,一些思路和细节。

一.安装并配置 我们选择使用react-router实现路由效果 yarn add react-router-dom下载后需要对Route进行引入&#xff0c;是个内置的组件。该组件是有两个属性一个是path&#xff0c;一个是component&#xff0c;path是组件对应的路由&#xff0c;component是对应的组件 二.…

蓝帽杯 取证2022

网站取证 网站取证_1 下载附件 并解压 得到了一个文件以及一个压缩包 解压压缩包 用火绒查病毒 发现后门 打开文件路径之后 发现了一句话木马 解出flag 网站取证_2 让找数据库链接的明文密码 打开www文件找找 查看数据库配置文件/application/database.php&#xff08;CodeI…

php如何对接伪原创api

在了解伪原创api的各种应用形态之后&#xff0c;我们继续探讨智能写作背后的核心技术。需要说明的是&#xff0c;智能写作和自然语言生成、自然语言理解、知识图谱、多模算法等各类人工智能算法都有紧密的关联&#xff0c;在百度的智能写作实践中&#xff0c;常根据实际需求将多…

C++11时间日期库chrono的使用

chrono是C11中新加入的时间日期操作库&#xff0c;可以方便地进行时间日期操作&#xff0c;主要包含了&#xff1a;duration, time_point, clock。 时钟与时间点 chrono中用time_point模板类表示时间点&#xff0c;其支持基本算术操作&#xff1b;不同时钟clock分别返回其对应…