штука долгая, хочу запускать её только один раз для пачки тестов, которые будут смотреть на одни и те же результаты
class DoStuffOnce:
target: str
@pytest.fixture(scope='class', autouse=True)
def run_long_stuff(self):
assert self.target
self.output = f'{self.target} ok: foo'
print(self.output)
def check(self, to_check):
assert f'ok: {to_check}' in self.output
class TestSomething(DoStuffOnce):
target = 'first'
def test_first(self):
self.check('foo')
но увы,
def test_first(self):
> self.check('foo')
def check(self, to_check):
> assert f'ok: {to_check}' in self.output
E AttributeError: 'TestSomething' object has no attribute 'output'
видимо, я неправильно варю scope=class, хотя по доке как будто бы это то что нужно: Fixtures are created when first requested by a test, and ... destroyed during teardown of the last test in the class.
ЧЯДНТ?
Чет вообще не понятно, что ты делаешь
интеграционный тест для софтины, которая долго бежит, выплёвывает оутпут, и в этом оутпуте должно быть несколько интересующих меня фрагментов запуск с набором параметров — один класс, проверка фрагментов — несколько def test_x() в этом классе хочу не запускать софтину несколько раз с одними и теми же параметрами
выкинь классы и напиши нормальную фикстуру и передавай ее в тест функцию
ок, как тогда должна выглядеть "нормальная фикстура", инициализация которой будет происходить единожды для уникального параметра?
Фикстура не должна быть методом класса, делаешь отдельно фикстуру и указываешь скоуп, какой тебе надо (module, class, session). Дальше передаешь её аргументом или в декораторе
@pytest.fixture(scope='class') def run_long_stuff(rls_arg): c = Checker(f'{rls_arg} ok: foo') print(f'OUT::: ${c.out}') return c class TestClass: @pytest.mark.parametrize('rls_arg', ['sometarget']) def test_first(self, run_long_stuff): run_long_stuff.check('foo') @pytest.mark.parametrize('rls_arg', ['sometarget']) def test_second(self, run_long_stuff): run_long_stuff.check('foo') выдало: ScopeMismatch: You tried to access the 'function' scoped fixture 'rls_arg' with a 'class' scoped request object, involved factories test/inh_test.py:9: def run_long_stuff(rls_arg) на всякий случай уточняю, что фикстуры в pytest я вижу второй раз в жизни
про скоупы фикстур прочитай
восхитительный ответ! прочитал https://docs.pytest.org/en/stable/fixture.html#fixture-scopes Fixtures are created when first requested by a test, and are destroyed based on their scope: class: the fixture is destroyed during teardown of the last test in the class. вон фикстура, скоуп class, должна создасться при первом обращении (в test_first), и уничтожиться после последнего (после test_second) дальше что?)
может быть тебе нужно его в самом class и объявить? сейчас ты хочешь скоуп модуля, имея функцию вне класса.
Ты уверен что тебе скоуп класс нужен. Ты же используешь его в каждом методе с разным аргументом
Убери скоуп класс, и добавь indirect=True в parametrize, тогда должно заработать
абсолютно уверен, погляди внимательнее, там одинаковые аргументы функционал который бы хотелось иметь в идеале, в голове выглядит как-то так: class RunApp: ... def run(self): output = subprocess.check_output(['app'] + self.run_parameters) def output_contains(self, regex): ... def output_not_contains(self, regex): ... class TestWithFoo(RunApp): run_parameters = ['--foo'] def test_a_mentioned(self): assert self.output_contains('AAA is x') def test_b_not_mentioned(self): assert self.output_not_contains('BBB') class TestWithBar(RunApp): run_parameters = ['--bar'] def test_b_mentioned(self): assert self.output_contains('BBB') соответственно, run() видится как @pytest.fixture(autouse=True, scope='class'), которая запускается один раз для блока TestWithFoo и один раз для TestWithBar в крайнем случае — окей, если путест не могёт в такое наследование как у меня, когда все проверки определены в базовом классе, то сойдёт и возвращение проверяльщика из фикстуры, class TestWithFoo: def test_a_mentioned(self, app_output): assert.app_output.contains(...)
Убери тогда аргумент из фикстуры и вешай декоратор на тест класс @pytest.mark.usefixtures('run_long_stuff')
если я уберу аргумент из фикстуры, как она узнает что в class TestWithFoo нужно запускаться с одними аргументами, а в class TestWithBar с другими?
Сделать несколько фикстур
Обсуждают сегодня