python - 并行获取每个浏览器的 selenium 驱动程序
问题描述
我正在寻找一种在云测试提供商上并行运行多个浏览器功能的方法。测试是用python编写的。我想我大部分时间都在那里,但我无法让每个浏览器的驱动程序都到tearDown
. 该项目将对多个站点进行测试,并针对多个平台、浏览器、浏览器版本和屏幕尺寸运行。现在我有一个概念,大多数可重复的步骤将位于项目的顶层,所有子目录(即单个站点)将只导入全局模块。现在这只是多个浏览器的设置。这样我就可以将每个子目录保留为测试本身。这是我所拥有的一个非常精简的示例。
项目结构看起来像
├── initializer.py
└── sites
├── site1
│ ├── test1.py
│ ├── test2.py
│ ├── requirements.txt
│ ├── setup.py
│ └── test.py
└── site2
├── test1.py
├── test2.py
├── requirements.txt
├── setup.py
└── test.py
这将是设置所有内容并导入到子目录/站点的顶层initializer.py
#!/usr/bin/env python
import os
import unittest
from threading import Thread
from selenium import webdriver
from desired_capabilities import *
API_EMAIL = os.environ["CBT_EMAIL"]
API_AUTH = os.environ["CBT_AUTH"]
class Setup(unittest.TestCase):
def __init__(self):
self.browsers = []
self.browsers_waiting = []
self.threads = []
def setUp(self):
for platform in platforms:
# win
if platform == "Windows 10":
for version in win_10_chrome_versions:
self.gen_browser("Chrome", version, platform)
for version in win_10_ff_versions:
self.gen_browser("Firefox", version, platform)
for version in win_10_ie_versions:
self.gen_browser("Internet Explorer", version, platform)
# mac
elif platform == "Mac OSX 10.12":
for version in mac_10_12_chrome_versions:
self.gen_browser("Chrome", version, platform)
for version in mac_10_12_ff_versions:
self.gen_browser("Firefox", version, platform)
for version in mac_10_12_safari_versions:
self.gen_browser("Safari", version, platform)
for i, browser in enumerate(browsers):
thread = Thread(target=self.get_browser_and_wait, args=[browser])
self.threads.append(thread)
thread.start()
for thread in self.threads:
thread.join()
print ("\n\tAll browsers are setup and ready\n")
for i, browser in enumerate(browsers_waiting):
self.tearDown(browser) # I know this doesn't work, it's the approach I would like. tearDown doesn't allow another argument
def get_browser_driver(self, caps):
return webdriver.Remote(
desired_capabilities=caps,
command_executor="http://%s:%s@hub.crossbrowsertesting.com:80/wd/hub" % (API_EMAIL, API_AUTH)
)
def gen_browser(self, browser, version, platform):
for resolution in desktop_screen_resolution:
caps = {}
caps['platform'] = platform
caps['browserName'] = browser
caps['version'] = version
caps['screenResolution'] = resolution
caps['name'] = 'Login Form Example'
caps['build'] = '1.0'
caps['record_video'] = 'false'
caps['record_network'] = 'false'
print ("Browser %s %s is now set up for %s at %s\n" % (browser, version, platform, resolution))
self.browsers.append(caps)
def get_browser_and_wait(self, browser_data):
print ("Starting %s %s for %s at %s\n" % (browser_data["browserName"], browser_data["version"], browser_data["platform"], browser_data["screenResolution"]))
driver = self.get_browser_driver(browser_data)
browsers_waiting.append({"data": browser_data, "driver": driver})
print ("%s %s at %s for %s is ready\n" % (browser_data["browserName"], browser_data["version"], browser_data["screenResolution"], browser_data["platform"]))
while len(self.browsers_waiting) < len(self.browsers):
print ("Working on %s for %s.... please wait" % (browser_data["browserName"], browser_data["platform"]))
time.sleep(10)
def tearDown(self):
# This is where I'm stumpped
# looping through the browsers_waiting doesnt work either
if (self.driver != None):
self.driver.close()
self.driver.quit()
然后这是一个myproject/sites/sitename/test.py
基本上是主要的入口点脚本,它将调用所有测试
#!/usr/bin/env python
from unittest import TestSuite, TextTestRunner, TestLoader
from example import exampleTest
def suite():
loader = TestLoader()
suite = TestSuite()
suite.addTest(loader.loadTestsFromModule(exampleTest))
return suite
if __name__ == '__main__':
runner = TextTestRunner(verbosity=2)
runner.run(suite())
这是我在子/站点目录中的示例测试myproject/sites/sitename/example.py
#!/usr/bin/env python
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from initializer import Setup
from elements import Element as element
class exampleTest(Setup):
def test_Header(self):
for i, browser in enumerate(Setup().browsers_waiting):
# this does not work
driver = browser["driver"]
self.test_result = None
try:
driver.get('https://www.somewebsite.com')
driver.implicitly_wait(20)
elem = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, element.searchTitle))
)
headerText = elem.text
expectedHeaderText = 'Some Header'
self.assertEqual(expectedHeaderText, headerText)
self.test_result = 'pass'
except AssertionError as e:
print ("Something went wrong. Error is %s\n" % e)
self.test_result = 'fail'
raise
if __name__ == '__main__':
unittest.main()
我什至不确定这是否可能,或者我以这种方式设置它的方法甚至是最好的方法。我正在苦苦挣扎的地方是,一旦设置了所有浏览器,就能够调用单独的测试,和/或我无法访问每个浏览器的单独驱动程序。当您将它们全部推入浏览器数组时,self.driver 不再可用。
仅供参考:我在这里从 CBT 获得了很多这个想法:https ://github.com/crossbrowsertesting/selenium-python/blob/master/parallel/multithreaded/parallel.py
解决方案
我不是线程专家,也不是 python unittest 模块专家,如果我的回答不能帮助您解决问题,非常抱歉。
话虽如此,在您的 example.py 模块中,方法 test_Header 依赖于从初始化模块继承的类 Setup 中定义的实例 dict browsers_waiting。当方法 get_browser_and_wait 被执行时,有问题的 dict 会填充键值对。
所以在这一点上,如果方法 get_browser_and_wait 从未被调用,你正在循环一个空的字典
def test_Header(self):
for i, browser in enumerate(Setup().browsers_waiting):
# this does not work
driver = browser["driver"]
self.test_result = None
再说一遍,我不知道 unitest 模块是如何工作的,并且这个 dict 在引用时应该有一些值。
推荐阅读
- r - 在R中将行扩展到多列
- javascript - HTML 元素 - “值”属性或属性是否存在?
- python - 在字典网格中查找最近的键
- go - 如何创建扩展类型
- python - 尝试编译时出现python错误“以'\ xe9'开头的非UTF-8代码”
- sql-server - 如何根据同一数据库中的输入计算新列
- java - (Android java, JSON) 为什么它会丢失存储的值?
- html - CSS3 滑动渐变动画 - 它是如何工作的
- javascript - 使用 vue 创建 Excel 插件时。如何根据 Excel 笔记本上的数据计算属性?
- c# - C# - Microsoft Word VSTO - 更新表单中的 ProgressBar