Как правильно настроить и разорвать мой класс pytest с помощью тестов?
Я использую selenium для сквозного тестирования и не могу понять, как использовать методы setup_class
и teardown_class
.
Мне нужно настроить браузер в методе setup_class
, затем выполнить несколько тестов, определенных как методы класса, и, наконец, выйти из браузера в методе teardown_clas
.
Но логически это кажется плохим решением, потому что на самом деле мои тесты будут работать не с классом, а с объектом. Я передаю параметр self
внутри каждого метода тестирования, чтобы получить доступ к переменным объектов:
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_class
и teardown_class
?
Ответы
Ответ 1
В соответствии с Фиксация/выполнение кода разрыва использование addfinalizer
является "историческим".
Как историческое примечание, другой способ написать код разрыва - это принять объект запроса в вашу функцию привязки и вызывать его request.addfinalizer один или несколько раз:
Нынешняя лучшая практика настройки и разгона заключается в использовании yield
import pytest
@pytest.fixture()
def resource():
print("setup")
yield "resource"
print("teardown")
class TestResource(object):
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 ===
Ответ 2
Когда вы пишете "тесты, определенные как методы класса", вы действительно имеете в виду методы класса (методы, которые получают его class в качестве первого параметра) или просто обычные методы (методы, которые получают экземпляр как первый параметр)?
Так как ваш пример использует 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 приспособлениями, так как они являются более мощной концепцией.
Ответ 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
Это может помочь 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, он записывает подробности того, когда он начинает выполнение, когда он заканчивает выполнение, и то же самое для методов.
Вы можете добавить другие шаги по настройке и демонтажу, которые вы можете выполнить в соответствующих местах.
Надеюсь, это поможет!
Ответ 5
Ваш код должен работать так, как вы ожидаете, если вы добавите декораторы @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/