使用 Appium 进行 WPF 自动化

news2024/12/23 16:16:49

文章目录

  • 关于
  • 1 环境准备
  • 2 集成单元测试
  • 3 新增基本测试代码
  • 4 测试 WPF 程序
  • 5 启动测试

关于

参考链接:Get Your WPF Apps Automated With Appium

Appium官网:http://appium.io/docs/en/2.0/quickstart

1 环境准备

一、下载 Windows Application Driver,该驱动可以用于测试 UWP、WPF、WinForm、Win32 程序

二、下载 WinAppDriver 源码,具体的一些内容可以参考源码中的示例

如果需要自己编译 UIRecorder(后面使用到的元素选择器),可以打开 WinAppDriver 源码进行编译,或者你可以用我已经编译好的 exe 文件

UIRecorder:点此下载
编译时间:2023-05-09
编译平台:Visual Studio 2022
git branch: master
git commit: 9c561a5

三、打开系统的 开发者模式

打开 Window 设置,搜索 developer,启用开发者模式

在这里插入图片描述

2 集成单元测试

新建一个单元测试项目 MyAPP

给该项目添加 nuget 包 Appium.WebDriver

在这里插入图片描述

3 新增基本测试代码

新建类 TestsBase,新增方法 StartWinAppDriver 和 Initialize

public class TestsBase
{
	private const string WindowsApplicationDriverUrl = "http://127.0.0.1:4723";
	private const string ApplicationPath = @"..\..\..\..\MyAPP\bin\Debug\\MyAPP.exe";
	private const string DeviceName = "WindowsPC";
	private const int WaitForAppLaunch = 5;
	private const string WinAppDriverPath = @"C:\Program Files (x86)\Windows Application Driver\WinAppDriver.exe";
	private static Process winAppDriverProcess;
	public WindowsDriver<WindowsElement> AppSession { get; private set; }
	public WindowsDriver<WindowsElement> DesktopSession { get; private set; }
	
	private static void StartWinAppDriver()
    {
        ProcessStartInfo psi = new ProcessStartInfo(WinAppDriverPath);
        psi.UseShellExecute = true;
        psi.Verb = "runas"; // run as administrator
        winAppDriverProcess = Process.Start(psi);
    }

    public void Initialize()
    {
        StartWinAppDriver();
        var appiumOptions = new AppiumOptions();
        appiumOptions.AddAdditionalCapability("app", ApplicationPath);
        appiumOptions.AddAdditionalCapability("deviceName", DeviceName);
        appiumOptions.AddAdditionalCapability("ms:waitForAppLaunch", WaitForAppLaunch);
        this.AppSession =
            new WindowsDriver<WindowsElement>(new Uri(WindowsApplicationDriverUrl), appiumOptions);
        Assert.IsNotNull(AppSession);
        Assert.IsNotNull(AppSession.SessionId);
        AppSession.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(1.5);
        AppiumOptions optionsDesktop = new AppiumOptions();
        optionsDesktop.AddAdditionalCapability("app", "Root");
        optionsDesktop.AddAdditionalCapability("deviceName", DeviceName);
        DesktopSession = new WindowsDriver<WindowsElement>(new Uri(WindowsApplicationDriverUrl), optionsDesktop);
    }
}

新增方法

public void Cleanup()
{
    // Close the session
    if (AppSession != null)
    {
        AppSession.Close();
        AppSession.Quit();
    }
    // Close the desktopSession
    if (DesktopSession != null)
    {
        DesktopSession.Close();
        DesktopSession.Quit();
    }
}
public static void StopWinappDriver()
{
    // Stop the WinAppDriverProcess
    if (winAppDriverProcess != null)
    {
        foreach (var process in Process.GetProcessesByName("WinAppDriver"))
        {
            process.Kill();
        }
    }
}

新增一些操作元素的基本方法

protected void SelectAllText()
{
    Actions action = new Actions(AppSession);
    action.KeyDown(Keys.Control).SendKeys("a");
    action.KeyUp(Keys.Control);
    action.Perform();
}

protected void PerformDelete()
{
    Actions action = new Actions(AppSession);
    action.SendKeys(Keys.Delete);
    action.Perform();
}

protected void PerformEnter()
{
    Actions action = new Actions(AppSession);
    action.SendKeys(Keys.Enter);
    action.Perform();
}

protected void WriteText(string text)
{
    Actions action = new Actions(AppSession);
    action.SendKeys(text);
    action.Perform();
}

public WindowsElement FindByName(string name)
{
    return this.AppSession.FindElementByName(name);
}
public WindowsElement FindById(string id)
{
    return this.AppSession.FindElementByAccessibilityId(id);
}

4 测试 WPF 程序

新建类 UnitTest,继承自 TestBase

[TestClass]
public class UnitTest : TestBase
{
    private const string BUTTON_NEW_DATA_BASE = "newDataBaseButton";
    [TestInitialize]
    public void TestInitialize()
    {
        this.Initialize();
    }

    [TestCleanup]
    public void TestCleanup()
    {
        this.Cleanup();
    }

    [ClassCleanup]
    public static void ClassCleanusp()
    {
        StopWinappDriver();
    }

    [TestMethod]

    [DataRow("我的库")]
    public void CreateDataBase(string dbName)
    {
        WindowsElement btn = this.FindById(BUTTON_NEW_DATA_BASE);
        Assert.IsNotNull(btn);
        btn.Click();
        Thread.Sleep(1000);
        this.WriteText(dbName);
        this.PerformEnter();
    }


}

然后打开我们的 WPF 主窗体的 xaml 代码

新增一个按钮,添加属性 AutomationProperties.AutomationId,和上面的 BUTTON_NEW_DATA_BASE 相对应

 <Button
      MinWidth="100"
      AutomationProperties.AutomationId="newDataBaseButton" />

5 启动测试

在 Visual Studio 2022 中,点击视图-测试资源管理器

找到我们新增的 UnitTest 类,右键运行,结果如下

在这里插入图片描述

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

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

相关文章

JVM 虚拟机栈

虚拟机栈概述 背景: 由于跨平台性的设计&#xff0c;Java 的指令都是根据栈来设计的。不同平台 CPU 架构不同&#xff0c;所以不能设计为基于寄存器的优点是跨平台, 指令集小&#xff0c;编译器容易实现&#xff0c;缺点是性能下降&#xff0c;实现同样的功能需要更多的指令 …

CVE-2023-21839 Weblogic RCE

前言 刷B站的时候给我推的一个WebLogic的比较新的漏洞&#xff0c;可以通过此漏洞直接达到RCE进行getShell的效果&#xff0c;于是就简单复现和分析一下&#xff0c;做个记录。 视频链接 漏洞简单分析 此漏洞是属于WebLogic的JNDI注入漏洞&#xff0c;漏洞造成的原因是Weblo…

《创新者的基因》读书笔记

本书是企业创新管理的研究成果&#xff0c;针对个人和企业如何培养、提升商业创新能力给出了行动指南&#xff0c;每一种能力都提供了很多训练小技巧&#xff0c;在此不一一列举&#xff0c;只写自己的读书笔记、对策和思考。 破坏性创新者的基因 发问&#xff1a;目的是提出…

Java字符串详解:概念、特点与常见的使用场景

Java字符串是开发中经常使用到的一种数据类型&#xff0c;使用它可以处理文本、URL、文件路径等多种类型的数据。本文将对Java字符串的概念、特点以及常见使用场景进行详细解释。本文将分为以下几个部分&#xff1a; String的概念和特点Java字符串常量池字符串的不可变性使用e…

LeetCode - 3. 无重复字符的最长子串

写在前面&#xff1a; 题目链接&#xff1a;LeetCode - 3. 无重复字符的最长子串 题目难度&#xff1a;中等 编程语言&#xff1a;C 一、题目描述 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s “abcabcbb” 输出: 3 解释…

【RabbitMQ】SpringAMQP

RabbitMQ 1.初识MQ 1.1.同步和异步通讯 微服务间通讯有同步和异步两种方式&#xff1a; 同步通讯&#xff1a;就像打电话&#xff0c;需要实时响应。 异步通讯&#xff1a;就像发邮件&#xff0c;不需要马上回复。 两种方式各有优劣&#xff0c;打电话可以立即得到响应&am…

快速了解C语言的基本元素

C语言是一种编程语言&#xff0c;和其它语言一样&#xff0c;也定义了自己的语法和词汇。学习C语言&#xff0c;首先要学习C语言的词汇&#xff0c;再学习C语言的语法规则&#xff0c;然后由词汇构成语句&#xff0c;由语句构成源程序&#xff0c;源程序也称为源代码或代码&…

ORB-SLAM2的稠密重建实战(1) — 流程与函数功能说明

目录 0 系统整体流程 1 输出信息 2 初始化文件 3 初始化并运行追踪线程Tracking Step1&#xff1a;地图初始化 Step2&#xff1a;初始化成功&#xff08;mbOnlyTracking&#xff09; Step3&#xff1a;局部地图跟踪TrackLocalMap() Step4&#xff1a;跟踪成功 Step5&a…

【EKF】卡尔曼滤波的二维应用实例

前言 在上期&#xff0c;使用一个简单的一维应用实例来加深了卡尔曼滤波的印象后&#xff0c;使用一个二维的例子来看一下卡尔曼的效果。使用一个自由落体的例子来说明&#xff0c;假设一个物体在重力作用下&#xff0c;速度由0开始做自由落体运动&#xff0c;有观测装置对该物…

自动化部署编译部署【.net core】

自动化部署编译部署【.net core】 github 自动化编译部署 .NET 程序&#xff0c;程序有两个服务&#xff0c;一个是api&#xff0c;一个是admin. 需要部署到两台机器上(测试和正式)&#xff0c;所以采用两个Action来处理 项目目录结构 root ├── Config │ ├── deploy …

【Linux】进程间通信 —— 共享内存

文章目录 &#x1f4d5; 共享内存的原理&#x1f4d5; 代码实现 & 深入理解共享内存shmget() 函数shmctl() 、shmdt()、shmat()特点 &#x1f4d5; 源代码comm.hppserver.ccclient.cc &#x1f4d5; 共享内存的原理 我们知道&#xff0c;如果想实现进程间通信&#xff0c;…

Linux Shell 实现一键部署subversion

subversion SVN是subversion的缩写&#xff0c;是一个开放源代码的版本控制系统&#xff0c;通过采用分支管理系统的高效管理&#xff0c;简而言之就是用于多个人共同开发同一个项目&#xff0c;实现共享资源&#xff0c;实现最终集中式的管理。 TortoiseSVN TortoiseSVN 是…

C语言函数大全-- t 开头的函数

C语言函数大全 本篇介绍C语言函数大全-- t 开头的函数 1. tan&#xff0c;tanf&#xff0c;tanl 1.1 函数说明 函数声明函数功能double tan(double x)计算 以弧度 x 为单位的角度的正切值&#xff08;double&#xff09;float tanf(float x)计算 以弧度 x 为单位的角度的正…

Spring Boot项目创建和使用

一、Spring Boot简介 1.概念 Spring Boot 就是 Spring 框架的脚⼿架&#xff0c;它就是为了快速开发 Spring 框架⽽诞⽣的。 2.优点 有快速集成框架&#xff0c;可以快速添加外部jar包内置web框架&#xff0c;可以直接运行可以快速部署&#xff0c;不依赖任何外部的web容器…

【牛客刷题专栏】0x26:JZ25 合并两个排序的链表(C语言编程题)

前言 个人推荐在牛客网刷题(点击可以跳转)&#xff0c;它登陆后会保存刷题记录进度&#xff0c;重新登录时写过的题目代码不会丢失。个人刷题练习系列专栏&#xff1a;个人CSDN牛客刷题专栏。 题目来自&#xff1a;牛客/题库 / 在线编程 / 剑指offer&#xff1a; 目录 前言问…

MATLAB 之 数值数据,矩阵的表示和变量及其操作

文章目录 一、数值数据1. 数值数据类型的分类1.1 整型1.2 浮点型1.3 复型 2. 数据的输出格式 二、矩阵的表示1. 矩阵的建立1.1 直接输入法建立矩阵1.2 已建好的矩阵建立更大的矩阵 2. 冒号表达式3. 矩阵元素的引用3.1 矩阵元素的引用方式3.2 利用冒号表达式获得子矩阵3.3 利用空…

Spring执行流程Bean生命周期

Spring执行流程 说明&#xff1a;这里只是说的大概流程&#xff0c;不是严格按照源码上一步一步说的。 简单来说&#xff0c;分为下边四个步骤&#xff1a; 启动Spring容器实例化Bean&#xff08;分配内存空间&#xff09;将Bean注册到Spring当中&#xff08;存操作&#xf…

【常用 Linux 命令的基本使用】总结篇(附必要的 Ubuntu 截图)

本文目录 1. 常用 Linux 命令的基本使用1.1 学习 Linux 终端命令的原因1.2 常用 Linux 命令的基本使用1.3 自动补全 2. Linux 终端命令格式2.1 终端命令格式2.2 查阅命令帮助信息&#xff08;了解&#xff09; 3. 文件和目录常用命令3.1 查看目录内容3.1.1 终端实用技巧3.1.2 l…

shell数组

目录 一&#xff1a;数组定义方法 1、方法一 ​ 2、方法二 ​3、方法三 ​4、方法四 5、判断数组是否完整 &#xff08;1&#xff09;方法一 &#xff08;2&#xff09;方法二&#xff1a;通过脚本 二&#xff1a;获取数组值 1、获取数组长度 2、获取数组数据列表 3、…

本地部署 Stable Diffusion web UI

本地部署 ChatGLM-6B 0. 什么是 Stable Diffusion1. 什么是 Stable Diffusion web UI2. Github 地址3. 安装 Miniconda34. 创建虚拟环境5. 安装 Stable Diffusion web UI6. 启动 Stable Diffusion web UI7. 访问 Stable Diffusion web UI8. 其他 0. 什么是 Stable Diffusion S…