WinAppDriver 自动测试 winform 自动测试的部署

老师让我们用WinAppDriver做做自动测试,网上的中文资料确实比较少,靠自己可怜的英语水平看看英文资料加上几天的摸爬滚打终于是配置成功了,现在来给总结一下WinAppDriver的配置过程,主要针对的是基于C#开发的winform桌面程序

首先在github上下载 WinAppDriver :

https://github.com/microsoft/WinAppDriver

https://github.com/Microsoft/WinAppDriver/releases

另外针对桌面一些应用程序,github上提供了一些基于各种代码的测试样例,比如C#的就在

https://github.com/microsoft/WinAppDriver/tree/master/Samples/C%23

当然很熟练的大牛一看就上手了,不过我看了很久确实怎么看懂,毕竟一直没有什么开发经验。

WinAppDriver 安装完成后运行会如图所示:就是成功了

接着就是代码处的配置问题了,新建一个测试,在AppSession中做如下配置,具体代码可见上文中的github,自己只需要做一些小改动即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
protected const string DriverUrl = "http://127.0.0.1:4723";
        private const string AppId = @"C:\Users\MSI\Desktop\团队项目 界面测试\oneRichText\bin\Debug\一个.exe";
        private const string AppWorkingDir = @"C:\Users\MSI\Desktop\团队项目 界面测试\oneRichText\bin\Debug";

        protected static WindowsDriver<WindowsElement> session;

        public static void Setup(TestContext context)
        {
            // Launch a new instance of application
            if (session == null)
            {
                // Create a new session to launch application
                var appCapabilities = new DesiredCapabilities();
                appCapabilities.SetCapability("app", AppId);
                appCapabilities.SetCapability("appWorkingDir", AppWorkingDir);
                //appCapabilities.SetCapability("deviceName", "WindowsPC");这里是另一种写法
                session = new WindowsDriver<WindowsElement>(new Uri(DriverUrl), appCapabilities);
                Assert.IsNotNull(session);
                Assert.IsNotNull(session.SessionId);

                // Set implicit timeout to 1.5 seconds to make element search to retry every 500 ms for at most three times
                session.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(1.5));
            }
        }

首先 protected const string DriverUrl = "http://127.0.0.1:4723";保证与开始WinAppDriver里面相同即可,然后其他写法基本就是照搬过来的,只是有细微的区别。

就是这一句,appCapabilities.SetCapability("deviceName", "WindowsPC"); 询问了一下这两句的区别应该是自动化测试在运行时选择的程序的范围,如果使用我正在使用的那一句那么调用session.FindElement等等的时候就只会找到当前这个目录下运行的程序,具体我没有验证过,但是目前就我本身的需求而言只需要选择属于本程序之内的元素,我暂时没有多做探究。

紧接着是这个public static void Setup(TestContext context),我只是把这个测试启动抽象为了一个方法,如果不需要这种写法,直接把整个 Setup函数改成[TestMethod]就是一个启动程序的启动测试了。

如果要使用了Setup就可以在单元测试中申明初始化和关闭两步:

1
2
3
4
5
6
7
8
9
10
11
        [ClassInitialize]
        public static void ClassInitialize(TestContext context)
        {
            Setup(context);
        }

        [ClassCleanup]
        public static void ClassCleanup()
        {
            TearDown();
        }

其他的测试方法照常写即可。

自动测试的原理是 基于一下几种函数对于桌面程序中的元素进行选择,然后进行点击等操作来完成一个自动的过程

Client API Locator Strategy Matched Attribute Example
FindElementByAccessibilityId accessibility id AutomationId AppNameTitle
FindElementByClassName class name ClassName TextBlock
FindElementById id RuntimeId (decimal) 42.333896.3.1
FindElementByName name Name Calculator
FindElementByTagName tag name LocalizedControlType (upper camel case) Text

当测试写好后,保证后台WinAppDriver正在运行,然后点击开始测试,就可以看到桌面程序自行启动开始运行,具体运行鼠标如何点击就取决于你的代码如何写的了。接下来就是不断完善自己的代码的问题了。

接下来说几个自己的配置是遇到的坑:

显示函数被弃用,这里其实是因为NuGet里面几个包的版本太高了,太高的版本会废弃这个函数,具体新的替代怎么写,我也不太清楚,但是现在又需要用,怎么办?

这里就直接还原以前的版本,其实3.8.0.0好像也可以,但是为了抱歉我还原到了3.0.0.1,当然如果显示根本不认识这个几个函数,那就是根本就没添加这几个包,按照版本添加即可。

当真正运行自己的程序的时候,有时候会发现那几个函数无法满足自己的要求,比如我要右键点击怎么办?双击怎么办?有些控件选择到了但是鼠标不在正确的位置,这个的正确解决方法我也不清楚,但是我个人暂时是这样解决问题的:

使用鼠标操作的函数库,但是C#本身带的类库中没有关于鼠标操作的函数库,需要引用微软的dll,在visual studio中使用 nuget添加 mshtml 即可(Microsoft.mshtml)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Runtime.InteropServices;

    namespace workhelper
    {
        class MouseHelper
        {
            [System.Runtime.InteropServices.DllImport("user32")]
            public static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
            //移动鼠标
            public const int MOUSEEVENTF_MOVE = 0x0001;
            //模拟鼠标左键按下
            public const int MOUSEEVENTF_LEFTDOWN = 0x0002;
            //模拟鼠标左键抬起
            public const int MOUSEEVENTF_LEFTUP = 0x0004;
            //模拟鼠标右键按下
            public const int MOUSEEVENTF_RIGHTDOWN = 0x0008;
            //模拟鼠标右键抬起
            public const int MOUSEEVENTF_RIGHTUP = 0x0010;
            //模拟鼠标中键按下
            public const int MOUSEEVENTF_MIDDLEDOWN = 0x0020;
            //模拟鼠标中键抬起
            public const int MOUSEEVENTF_MIDDLEUP = 0x0040;
            //标示是否采用绝对坐标
            public const int MOUSEEVENTF_ABSOLUTE = 0x8000;
            [DllImport("user32.dll")]
            public static extern bool SetCursorPos(int X, int Y);
        }
    }

具体操作可以在网上查一下这里就不多赘述了,这就可以解决所有问题了。

接着还有一个地方我也苦恼过很久,就是有Form1打开了一个新窗口Form2,但是新窗口Form2里面的元素选择不到,这里我把上面的方法替换成下面就可以了,以下是个人推测没有证实过:

ShowDialog应该是作为对话框打开,是Form1的一个子元素,因此find函数能找到,但是Show是作为一个独立的新进程窗口,所以选择不到,当然这个是猜测,具体是不是我也不清楚,但是问题解决了总是好的

1
2
3
4
5
Form2 newform = new Form2(this);
                newform.Show();

Form2 newform = new Form2(this);
                newform.ShowDialog();