背景
近期的⾃动化测试项⽬中有个关于测试内部IM通信软件的需求,在了解到各个客户端的相应技术栈实现以后,在mac中的应⽤使⽤的是electron 技术,我们也对相应的技术进⾏调研,此⽂记录⼀下在关于electron应⽤的⾃动化测试。
electron 简介
electron利⽤Chromium和Node.js,为使⽤ JavaScript,HTML 和 CSS 构建跨平台的桌⾯应⽤程序,可以实现代码⼀次编译,多端运⾏的效果,可以⽣成mac app, windows exe等,但是它编译出来的⽂件由于包含Chromium,所以体积⼀般会⽐较⼤。
使⽤selenium操作Chrome浏览器
先确定⼀下系统中的chrome浏览器的版本,由于selenium 操作Chrome浏览器需要使⽤到ChromeDriver,不同版本的Chrome对应着不同的ChromeDriver,如果不对应的话可能会失败。
然后到
https://chromedriver.chromium.org/downloads 这⾥下载对应的ChromeDriver,国内的⽤户如果访问不了的话可以使⽤淘宝镜像源
https://npm.taobao.org/mirrors/chromedriver
需要将chromedriver放到环境变量⾥,如果不放到环境变量⾥的话,也可以在代码中指定chromedriver的路径
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
driver = webdriver.Chrome()
# webdriver.Chrome 在初始化的时候也可以指定chromedriver路径,这种对于系统中有多个版本的
chromedriver⾮常有⽤
# driver = webdriver.Chrome(executable_path="/Users/qihoo/Desktop/chromedriver94")
driver.get("https://www.google.com")
assert "Google" in driver.title
elem = driver.find_element_by_name("q")
elem.clear()
elem.send_keys("360")
elem.send_keys(Keys.RETURN)
assert "No results found." not in driver.page_source
driver.close()
使⽤selenium操作electron应⽤
想要使⽤ selenium 操作electron app, ⾸先要确认的是该app使⽤的是哪个版本的Chromium那么该如何确认electron应⽤的Chromium版本号呢?
⼀般情况下,我们是测试的app都是由开发打包之后的app,对于这种应⽤,我们很难在代码上做些hook,如果我们打开chrome devTools⾯板,(mac下使⽤option+command+i), 在console标签中输⼊ process.versions 可以查看到 chrome 版本,那么最好不过了,可以直接去下载对应的chromedriver, 但是更多的时候这个 process 对象是没有定义的,如果想要在控制台使⽤process,在编写app时,应该加上
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true, contextIsolation: false //加上这个配置才可以在控制台使⽤process对象
}
})
更多的时候我们可以随便找⼀下版本的 chromedriver, 在初始化的过程中,如果程序报错了,会提示出app⽤的是哪个版本的chrome。
selenium.common.exceptions.SessionNotCreatedException: Message: session not created:
This version of ChromeDriver only supports Chrome version 94
Current browser version is 80.0.3987.86 with binary path /Applications/360家.app/Contents/MacOS/360家
这⾥有显示我当前的 chromedriver 版本号是94,但是要被测试的应⽤的版本号是80,所以就知道了需要下载哪个版本的 chromedriver了。
我们使⽤electron来创建⼀个mac 应⽤,代码使⽤官⽅提供的示例,
https://www.electronjs.org/zh/docs/latest/tutorial/quick-start
但是打包我这⾥和官⽅的不太⼀样。
1. 创建项⽬
mkdir electroltest
cd electrontest
npm init -y
2. 安装electron 和相应的打包⼯具
npm install electron electron-packager electron-installer-dmg --save
3. 修改 package.json
{
"name": "electroltest",
"version": "1.0.0",
"description": "",
"main": "main.js", //修改为main.js
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "electron .", // 添加⼀个启动指令
"build": "electron-packager .", //添加打包指令
"dmg": "electron-installer-dmg ./electroltest-darwin-x64/electroltest.app/
electroltest" // 添加⽣成dmg指令
},
"author": "",
"license": "ISC",
"dependencies": {
"electron": "^15.1.2",
"electron-installer-dmg": "^3.0.0",
"electron-packager": "^15.4.0"
}
}
4. 添加 main.js
const { app, BrowserWindow } = require('electron')
const path = require('path')
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
win.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
5. 添加index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello YYX!</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafeinline';"/>
</head>
<body>
<h1>Hello 360 质量效能 !</h1>
<p>
We are using Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
and Electron <span id="electron-version"></span>.
</p>
</body>
</html>
6. 添加 proload.js
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}
for (const type of ['chrome', 'node', 'electron']) {
replaceText(`${type}-version`, process.versions[type])
}
})
写完代码以后可以使⽤npm run start 看下效果,是否可以正常的显示electron应⽤
如果正常显示则可以进⾏打包操作
7. 打包electron应⽤
这⾥只是将electron 应⽤打成app,并没有⽣成dmg安装包
npm run build #这⾥是由于在package.json中定义了build指令,如果没有定义也可以运⾏ npxelectron-packager
8. ⽣成mac下的 dmg 安装包
npm run dmg # 同build指令,这⾥也可以使⽤ npx electron-installer-dmg ./electroltestdarwin-x64/electroltest.app/ electroltest
如果⼀切顺利,则会在当前⽬录下⽣成 electroltest.dmg ⽂件 ,双击这个⽂件就可以安装在mac中了
接下来我们来写⼀个简单的测试,就是打开app,查看⼀下html,再跳转到google,输⼊⼀些⽂字,再点击搜素按钮
该electron 应⽤安装的位置是
/Applications/electroltest.app/Contents/MacOS/electroltest
自己根据安装的位置进行相应的修改
1. 安装 selenium
pip install selenium
2. 写测试⽤例
# -*- coding: utf-8 -*-
"""
-------------------------------------------------
File Name:eletest
Description : electrol⾃动化测试
Author : qihoo
date:2021/10/14
-------------------------------------------------
"""
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
options = webdriver.ChromeOptions()
options.binary_location = "/Applications/electroltest.app/Contents/MacOS/electroltest"
driver = webdriver.Chrome(chrome_options=options)
time.sleep(3)
print(driver.page_source)
driver.get("http://www.google.com")
elem = driver.find_element_by_name("q")
elem.clear()
elem.send_keys("360") # 这⾥也可以输⼊中⽂
elem.send_keys(Keys.RETURN)
driver.close()
driver.quit()
这⾥⽐较重要的是定义 options.binary_location 需要设置为 electron 应⽤的路径
使⽤selenium操作已经打开的electron应⽤
以上⽅式我们其实是重新打开了某个app, 但是更多的时候,我们是期望测试⼀个已经打开的app,试想⼀下如下的场景,某个app需要登录,登录的⽅式⼜⽐较复杂,扫码登录或者短信登录,或者有验证码,但是如果成功登录以后,⼀段时间以后再次打开就不会进⼊到登录界⾯,此时,我们不希望每次运⾏⽤例的时候,都重新登录,这时,我们就需要使⽤ selenium 来测试⼀个打开着的应⽤。
使⽤ electron 构建的app, 在启动的时候可以加上⼀个⽤于调试的端⼝
/Applications/electroltest.app/Contents/MacOS/electroltest --remote-debugging-port=9222
这样就可以正常的启动应⽤的同时,也会开启远程调试功能,我们在使⽤selenium时,就可以直接对该app进⾏测试了⽽不需要再次重新打开⼀个新的app
这⾥的端⼝需要⼀个没有被占⽤的端⼝,初始化driver时可以
options = webdriver.ChromeOptions()
options.add_experimental_option("debuggerAddress", "127.0.0.1:9222") # 设置
debuggerAddress
driver = webdriver.Chrome(chrome_options=options)
通过上⾯的设置以后,我们就可以直接在打开着的应⽤上进⾏测试了,⾮常适合那种登录⽐较复杂的应⽤。
总结
使⽤ selenium 测试 electron 应⽤的测试有⼏个总结
找到对应的 chromedriver;
通过 binary_location 参数设置app路径;
对于测试打开着的app, 需要在app启动的时候添加远程调试参数 --remote-debugging-port
参考文献
https://selenium-python-zh.readthedocs.io/en/latest/index.html#
https://www.sqlpy.com/blogs/894258980