如何在 Python 中使用装饰器 运行 测试 cross-platform/browser?
How to run tests cross-platform/browser using decorator in Python?
我有一个测试套件如下:
import unittest
from selenium import webdriver
SAUCE_USERNAME = 'xxx'
SAUCE_ACCESS_KEY = 'xxx'
sauce = SauceClient(SAUCE_USERNAME, SAUCE_ACCESS_KEY)
browsers = [{"platform": "Mac OS X 10.9",
"browserName": "chrome",
"version": "31"},
{"platform": "Windows 8.1",
"browserName": "internet explorer",
"version": "11"}]
def on_platforms(platforms):
def decorator(base_class):
module = sys.modules[base_class.__module__].__dict__
for i, platform in enumerate(platforms):
d = dict(base_class.__dict__)
d['desired_capabilities'] = platform
name = "%s_%s" % (base_class.__name__, i + 1)
module[name] = new.classobj(name, (base_class,), d)
return decorator
@on_platforms(browsers)
class MyTestSuite(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.desired_capabilities['name'] = cls.id()
sauce_url = "http://%s:%s@ondemand.saucelabs.com:80/wd/hub"
cls.driver = webdriver.Remote(
desired_capabilities=cls.desired_capabilities,
command_executor=sauce_url % (SAUCE_USERNAME,SAUCE_ACCESS_KEY))
cls.driver.implicitly_wait(30)
def test_1from_sauce(self):
pass
def test_2from_sauce(self):
pass
@classmethod
def tearDownClass(cls):
cls.driver.quit()
if __name__ == "__main__":
unittest.main()
我的目标是在浏览器中 运行 test_1from_sauce 和 test_2from_sauce for browsers/platforms 而且我确实想在浏览器中连续执行这两个操作在 setUpClass 上设置。为了解释更多,我想打开浏览器并进行两项测试,然后退出该驱动程序并启动另一个驱动程序。
现在当我 运行 这段代码时,我得到这个错误:
TypeError:必须使用 SeleniumSauce_2 实例作为第一个参数调用未绑定方法 setUpClass()(取而代之)
我知道 class 和 subclass 声明中应该有一个修改,但我不知道我应该做什么或者我应该改变哪一部分。
已编辑:我省略了以下行并且它工作正常:
cls.desired_capabilities['name'] = cls.id()
您在问题中显示的代码缺少 sys
和 new
的导入。其次,我在添加正确的导入后 运行 你的代码时得到的错误不是你在问题中报告的错误,而是这个:
EE
======================================================================
ERROR: setUpClass (__main__.MyTestSuite_1)
----------------------------------------------------------------------
Traceback (most recent call last):
File "tests.py", line 33, in setUpClass
cls.desired_capabilities['name'] = cls.id()
TypeError: unbound method id() must be called with MyTestSuite_1 instance as first argument (got nothing instead)
我省略了第二个 ERROR
,它与上面相同,只是它用于 MyTestSuite_2
而不是 MyTestSuite_1
。问题很清楚。您调用 cls
的 id()
成员,但 id()
是一个 实例方法 而不是 class 方法 所以它需要 class 的实例,而不是 class 本身。我不确定你最终想要什么,但如果你将它用于你的 setUpClass
,则错误不再发生并尝试连接:
@classmethod
def setUpClass(cls):
cls.desired_capabilities['name'] = cls.__name__
sauce_url = "http://%s:%s@ondemand.saucelabs.com:80/wd/hub"
cls.driver = webdriver.Remote(
desired_capabilities=cls.desired_capabilities,
command_executor=sauce_url % (SAUCE_USERNAME, SAUCE_ACCESS_KEY))
cls.driver.implicitly_wait(30)
唯一的修改是方法的第一行。
顺便说一下,我不明白你为什么要使用 new.classobj
。一方面,new
模块已被弃用。其次,使用 type
内置而不是 new.classobj
工作。
我有一个测试套件如下:
import unittest
from selenium import webdriver
SAUCE_USERNAME = 'xxx'
SAUCE_ACCESS_KEY = 'xxx'
sauce = SauceClient(SAUCE_USERNAME, SAUCE_ACCESS_KEY)
browsers = [{"platform": "Mac OS X 10.9",
"browserName": "chrome",
"version": "31"},
{"platform": "Windows 8.1",
"browserName": "internet explorer",
"version": "11"}]
def on_platforms(platforms):
def decorator(base_class):
module = sys.modules[base_class.__module__].__dict__
for i, platform in enumerate(platforms):
d = dict(base_class.__dict__)
d['desired_capabilities'] = platform
name = "%s_%s" % (base_class.__name__, i + 1)
module[name] = new.classobj(name, (base_class,), d)
return decorator
@on_platforms(browsers)
class MyTestSuite(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.desired_capabilities['name'] = cls.id()
sauce_url = "http://%s:%s@ondemand.saucelabs.com:80/wd/hub"
cls.driver = webdriver.Remote(
desired_capabilities=cls.desired_capabilities,
command_executor=sauce_url % (SAUCE_USERNAME,SAUCE_ACCESS_KEY))
cls.driver.implicitly_wait(30)
def test_1from_sauce(self):
pass
def test_2from_sauce(self):
pass
@classmethod
def tearDownClass(cls):
cls.driver.quit()
if __name__ == "__main__":
unittest.main()
我的目标是在浏览器中 运行 test_1from_sauce 和 test_2from_sauce for browsers/platforms 而且我确实想在浏览器中连续执行这两个操作在 setUpClass 上设置。为了解释更多,我想打开浏览器并进行两项测试,然后退出该驱动程序并启动另一个驱动程序。
现在当我 运行 这段代码时,我得到这个错误: TypeError:必须使用 SeleniumSauce_2 实例作为第一个参数调用未绑定方法 setUpClass()(取而代之)
我知道 class 和 subclass 声明中应该有一个修改,但我不知道我应该做什么或者我应该改变哪一部分。
已编辑:我省略了以下行并且它工作正常:
cls.desired_capabilities['name'] = cls.id()
您在问题中显示的代码缺少 sys
和 new
的导入。其次,我在添加正确的导入后 运行 你的代码时得到的错误不是你在问题中报告的错误,而是这个:
EE
======================================================================
ERROR: setUpClass (__main__.MyTestSuite_1)
----------------------------------------------------------------------
Traceback (most recent call last):
File "tests.py", line 33, in setUpClass
cls.desired_capabilities['name'] = cls.id()
TypeError: unbound method id() must be called with MyTestSuite_1 instance as first argument (got nothing instead)
我省略了第二个 ERROR
,它与上面相同,只是它用于 MyTestSuite_2
而不是 MyTestSuite_1
。问题很清楚。您调用 cls
的 id()
成员,但 id()
是一个 实例方法 而不是 class 方法 所以它需要 class 的实例,而不是 class 本身。我不确定你最终想要什么,但如果你将它用于你的 setUpClass
,则错误不再发生并尝试连接:
@classmethod
def setUpClass(cls):
cls.desired_capabilities['name'] = cls.__name__
sauce_url = "http://%s:%s@ondemand.saucelabs.com:80/wd/hub"
cls.driver = webdriver.Remote(
desired_capabilities=cls.desired_capabilities,
command_executor=sauce_url % (SAUCE_USERNAME, SAUCE_ACCESS_KEY))
cls.driver.implicitly_wait(30)
唯一的修改是方法的第一行。
顺便说一下,我不明白你为什么要使用 new.classobj
。一方面,new
模块已被弃用。其次,使用 type
内置而不是 new.classobj
工作。