如何正确地设置和拆除带有测试的pytest类?

我使用硒端到端测试,我不知道如何使用setup_classteardown_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____del__方法而不是setup_classteardown_class?

279608 次浏览

当你写"定义为类方法的测试"时,你真的指的是类方法(接受作为第一个参数的方法)还是普通方法(接受实例作为第一个参数的方法)?

因为你的例子使用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_methodteardown_method,但如果你的设置/拆卸代码不需要知道测试上下文,可以忽略它。更多信息可以找到在这里

我还建议您熟悉py。test的固定装置,因为它们是一个更强大的概念。

正如@Bruno所建议的,使用pytest fixture是另一种解决方案,它可以用于两个测试类,甚至只是简单的测试函数。下面是一个测试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...

注意,在fixture中引用了stuff_i_setup,允许该对象为与之交互的测试的setuptorn down。您可以想象,这对于持久对象(例如假设的数据库或某些连接)非常有用,这些对象必须在每次测试运行之前清除,以保持它们之间的隔离。

根据夹具终结/执行拆卸代码,当前设置和拆卸的最佳实践是使用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 ===

另一种编写拆卸代码的方法是在fixture函数中接受request-context对象,并使用执行一次或多次拆卸的函数调用其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))

如果你添加了@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/

这可能会帮助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执行开始时,它会记录详细信息,当它开始执行时,当它结束执行时,方法也是如此。

您可以在相应的位置添加其他安装和拆卸步骤。

希望能有所帮助!

import pytest
class Test:
@pytest.fixture()
def setUp(self):
print("setup")
yield "resource"
print("teardown")


def test_that_depends_on_resource(self, setUp):
print("testing {}".format(setUp))

为了运行:

pytest nam_of_the_module.py -v

我不确定我在你最初的问题中得到了使用Selenium的细节,但如果你只是问如何使用更经典的setUp/tearDown风格,Pytest支持大多数单元测试功能,所以你可以这样做:

import unittest




class TestHello(unittest.TestCase):


def setUp(self):
print('running setUp')


def test_one(self):
print('running test_one')


def test_two(self):
print('running test_two')


def tearDown(self):
print('running tearDown')

生产:

$ pytest -s -v
====================== test session starts =======================
platform linux -- Python 3.8.2, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- /gnu/store/nckjv3ccwdi6096j478gvns43ssbls2p-python-wrapper-3.8.2/bin/python
cachedir: .pytest_cache
hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase('/tmp/test/.hypothesis/examples')
rootdir: /tmp/test
plugins: hypothesis-5.4.1
collected 2 items


test_hw.py::TestHello::test_one running setUp
running test_one
running tearDown
PASSED
test_hw.py::TestHello::test_two running setUp
running test_two
running tearDown
PASSED