Selenium 关于测试 windows 桌面 app,我有话说

xenafable · January 16, 2020 · 253 hits

前言

关于测试windows桌面app,不是桌面浏览器打开url!
我的需求:自动登录某应用,点击指定按钮,打开新的窗口。
结论:虽然经历曲折,最终还是找到了解决方案。
涉及:win32api 、appium、selenium。

因为刚刚接触,找了很多资料,可能是一开始查询的姿势不对,一直想的是如何操作windows的app(摔桌!),找到了两种方案,一种是vs自带的CodedUI Test,一个是win32的库。但我要测试的app是个套壳的web,再加上我用的是python,前者我就直接略过了。然后开始研究win32的库。

win32

这个库是python调用Windows api的库,有很多类,感觉基本所以的操作都能做。我用到的不多,因为没有想用这个做完整的自动化测试,就用到了几个基本的win32api、win32process、win32gui。虽然我最后没有用这个,不过也算是收获了一些知识。

安装

首先这个安装,我最开始安装的是pywin32,用的时候遇到了一些问题,虽然找到解决办法了,但在最后网友们说建议用pypiwin32,然后我就默默的卸载重装了,果然没那么多问题了...

<!-- old -->
$ pip install pywin32
<!-- new -->
$ pip install pypiwin32

模块使用

win32api

主要使用win32api执行一些命令,获取系统信息等,可以打开一个桌面app

win32api.ShellExecute(hwnd, op , file , params , dir , bShow)  
# ShellExecute这个函数接收6个参数,
# hwnd:父窗口的句柄,如果没有父窗口,则为0
# op:要进行的操作,为“open”、“print”或者空。
# file:要运行的程序,或者打开的脚本。
# params:要向程序传递的参数,如果打开的为文件,则为空。
# dir:程序初始化的目录。
# bShow:是否显示窗口。

获取app版本信息win32api.GetFileVersionInfo(app_name, os.sep)

win32process

在打开桌面app这一步,用win32process替代了win32api.ShellExecute,win32process能更好的管理打开的程序。

win32process.CreateProcess(appName, commandLine , processAttributes , threadAttributes , bInheritHandles ,dwCreationFlags , newEnvironment , currentDirectory , startupinfo )
# appName:可执行的文件名。
# commandLine:命令行参数。
# processAttributes:进程安全属性,如果为None,则为默认的安全属性。
# threadAttributes:线程安全属性,如果为None,则为默认的安全属性。
# bInheritHandles:继承标志。
# dwCreationFlags:创建标志。
# newEnvironment:创建进程的环境变量。
# currentDirectory:进程的当前目录。
# startupinfo :创建进程的属性。

CreateProcess返回一个列表,分别是进程句柄、线程句柄、进程ID,以及线程ID,拿到句柄之后就可以对它做任何操作了。
比如关闭该程序win32process.TerminateProcess(process_handle, 0)

win32gui

这个模块主要对图形界面进行操作,比如计算机中打开许多的应用程序;
我需要找到某一个程序,就可以根据窗口名称获取到对应的句柄win32gui.FindWindow(None, window_name),还可以获取窗口大小win32gui.GetWindowRect(handle)

spy++这个软件可以查看窗口控件名称。

不过呢,这个库对于原生的window应用来说比较友好,可以获取下拉菜单什么的,但是我需要操作的应用是electron写的,只能够勉强打开关闭应用,想要操作按钮输入啥的,得靠坐标定位,这就断了我的后路。

接着找解决方案的时候,有人提出来appium可以实现windows桌面的测试,我立马去研究了下appium怎么用。

appium

这个上手还是挺简单的,对于操作app的元素来说,就是些前端的知识。而启动来说,就是启一个appium server,然后就编写代码了。

desired_caps = {
'platformName': 'Windows',
'app': app,
'deviceName': 'WindowsPC'
}
driver = webdriver.Remote('http://{}:{}/wd/hub'.format('127.0.0.1', '4724'), desired_caps)

不过在我的windows上始终处于,driver获取不到,但应用默默的打开了的情况,日志会报错,找遍了也只找到了个WinAppDriver的issuehttps://github.com/microsoft/WinAppDriver/issues/1008,没有解决办法,只好放弃了。

停滞了几天之后,逛论坛的时候看到有人说selenium可以利用“欺骗”来达到运行windows app的目的,啪叽啪叽的就去试验了。

selenium

看了下官方文档,发现和appium的使用特别像,立马就上手了

options = webdriver.ChromeOptions()
options.add_argument("--remote-debugging-port=9222") # open devtools for operator element
options.add_experimental_option('w3c', False)
options.set_capability('platform', 'WINDOWS') # test windows app
options.set_capability('version', '10') # window version
options.binary_location = app # start up app path

try:
self.driver = webdriver.Remote(command_executor='http://{}:{}/wd/hub'.format(host, port), options=options)
except BaseException as e:
raise e

利用binary_location把要运行的app路径传进去,指定平台为WINDOWS,可以成功的启动应用并且拿到driver;
获取元素,执行js都没有问题

<!-- by class name -->
self.driver.find_elements_by_class_name('login')

<!-- js -->
app.execute_js('return window.location.href;')

不过在对输入框进行操作的时候,发现send_keys()输入的字符串,实际app上内容是不全的,一开始以为是selenium的原因,换成了PyKeyboard库测试,发现只要是输入一串字符都会出现这种问题,没有找出来是什么原因,只要简单粗暴的把字符串拆成列表一个一个写入了。

k = PyKeyboard()
for i in list(value):
k.tap_key(i)
time.sleep(0.1)

分布式测试

在使用的过程中发现还可以多机部署测试,在服务器起个server,

java -jar selenium-server-standalone-3.141.59.jar -role hub -maxSession 10 -port 8088

多台测试机上面下载好webdriver和selenium-server(grid),使用命令启动hub节点且连接到server,还可以指定webdriver的位置等,特别方便。

java -Dwebdriver.chrome.driver="D:\software\chromedriver_win32\2.44_chrome69-71\chromedriver.exe" -jar selenium-server-standalone-3.141.59.jar -role node -port 5555 -hub "http://127.0.0.1:8088/grid/register/" -browser "browserName=chrome,seleniumProtocol=WebDriver,maxInstances=5,platform=WINDOWS,version=10" -maxSession 5

然后在测试客户端配置指定使用的hub地址端口就好,后期还可以把这些执行的操作写成脚本在服务器端远程调用。
这个功能对于我想要同时在多个真机上进行操作很有用,同样的操作不同的账号就可以一次登录了。

最后

至此终于找到了最终解决方案,感谢广大的网友们!

实现了完整的代码,可以确定到目前为止是满足我的需求的,当然我的最终目的不是登录应用,不然光这些是远远不够的,这些操作对我来说只是辅助的条件,不过从这个过程中还是学到很多很多东西,为自己记录下来。

No Reply at the moment.
需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up