问题:如何为带有测试的pytest类正确设置和拆卸?
我正在使用硒进行端到端测试,但无法获得使用方法setup_class
和teardown_class
方法。
我需要在setup_class
方法中设置浏览器,然后执行一堆定义为类方法的测试,最后退出teardown_class
方法中的浏览器。
但是从逻辑上讲,这似乎是一个糟糕的解决方案,因为实际上我的测试不适用于类,而适用于对象。我self
在每个测试方法中传递参数,因此可以访问对象的vars:
class TestClass:
def setup_class(cls):
pass
def test_buttons(self, data):
# self.$attribute can be used, but not cls.$attribute?
pass
def test_buttons2(self, data):
# self.$attribute can be used, but not cls.$attribute?
pass
def teardown_class(cls):
pass
甚至为类创建浏览器实例似乎也不正确。应该为每个对象分别创建,对吗?
因此,我需要使用__init__
and __del__
方法代替setup_class
and teardown_class
?
回答 0
根据Fixture的完成/执行拆卸代码,当前设置和拆卸的最佳做法是使用yield
而不是return
:
import pytest
@pytest.fixture()
def resource():
print("setup")
yield "resource"
print("teardown")
class TestResource:
def test_that_depends_on_resource(self, resource):
print("testing {}".format(resource))
运行它会导致
$ py.test --capture=no pytest_yield.py
=== test session starts ===
platform darwin -- Python 2.7.10, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
collected 1 items
pytest_yield.py setup
testing resource
.teardown
=== 1 passed in 0.01 seconds ===
编写拆卸代码的另一种方法是,将一个request
-context对象接受到您的Fixture函数中,并request.addfinalizer
使用执行一次或多次拆卸的函数调用其方法:
import pytest
@pytest.fixture()
def resource(request):
print("setup")
def teardown():
print("teardown")
request.addfinalizer(teardown)
return "resource"
class TestResource:
def test_that_depends_on_resource(self, resource):
print("testing {}".format(resource))
回答 1
当您编写“定义为类方法的测试”时,您是说类方法(将其类作为第一个参数的方法)还是常规方法(将实例作为第一个参数的方法)?
由于您的示例使用self
了测试方法,因此我假设是后者,因此您只需要使用setup_method
:
class Test:
def setup_method(self, test_method):
# configure self.attribute
def teardown_method(self, test_method):
# tear down self.attribute
def test_buttons(self):
# use self.attribute for test
测试方法实例传递给setup_method
和teardown_method
,但是如果您的设置/拆卸代码不需要了解测试上下文,则可以忽略该方法。可以在这里找到更多信息。
我还建议您熟悉py.test的装置,因为它们是更强大的概念。
回答 2
这可能会有所帮助http://docs.pytest.org/en/latest/xunit_setup.html
在测试套件中,我将测试用例分组。对于安装和拆卸,我需要该类中的所有测试用例,我使用setup_class(cls)
和teardown_class(cls)
类方法。
对于每个测试用例的设置和拆卸,我使用setup_method(method)
和teardown_method(methods)
例:
lh = <got log handler from logger module>
class TestClass:
@classmethod
def setup_class(cls):
lh.info("starting class: {} execution".format(cls.__name__))
@classmethod
def teardown_class(cls):
lh.info("starting class: {} execution".format(cls.__name__))
def setup_method(self, method):
lh.info("starting execution of tc: {}".format(method.__name__))
def teardown_method(self, method):
lh.info("starting execution of tc: {}".format(method.__name__))
def test_tc1(self):
<tc_content>
assert
def test_tc2(self):
<tc_content>
assert
现在,当我运行测试时,当TestClass执行开始时,它将记录何时开始执行,何时结束执行以及方法的详细信息。
您可以在相应位置添加其他设置和拆卸步骤。
希望能帮助到你!
回答 3
正如@Bruno所建议的那样,使用pytest固定装置是另一种解决方案,可用于两个测试类甚至是简单的测试函数。这是测试python2.7函数的示例:
import pytest
@pytest.fixture(scope='function')
def some_resource(request):
stuff_i_setup = ["I setup"]
def some_teardown():
stuff_i_setup[0] += " ... but now I'm torn down..."
print stuff_i_setup[0]
request.addfinalizer(some_teardown)
return stuff_i_setup[0]
def test_1_that_needs_resource(some_resource):
print some_resource + "... and now I'm testing things..."
所以,跑步 test_1...
生成:
I setup... and now I'm testing things...
I setup ... but now I'm torn down...
该通知stuff_i_setup
是在夹具中引用,使该对象是setup
和torn down
为测试它与交互。您可以想象这对于持久性对象(例如假设的数据库或某些连接)很有用,必须在每次测试运行之前清除这些持久性对象以使它们隔离。
回答 4
添加@classmethod
装饰器后,您的代码应该可以按预期工作。
@classmethod
def setup_class(cls):
"Runs once per class"
@classmethod
def teardown_class(cls):
"Runs at end of class"
参见http://pythontesting.net/framework/pytest/pytest-xunit-style-fixtures/