英文:
Have a object created on a fixture accassible at setup_class, teardown_class, setup_method, and teardown_method
问题
我有一个 conftest.py 文件和一个测试文件(test_1.py)。下面是你的要求:
- library_instance 在 setup_class,teardown_class,setup_method,和 teardown_method 中都可调用,而不仅仅是测试用例中可用的。
- 在 teardown_method 中检查测试是否失败,如果失败则调用一些函数。
你需要的代码如下:
import pytest
import asyncio
from some_library import MyLibrary
@pytest.fixture()
def event_loop(request):
loop = asyncio.get_event_loop_policy().new_event_loop()
yield loop
loop.close()
@pytest.fixture(name="library_instance", scope='session')
def fixture_library_instance():
library = MyLibrary()
print("\nSetup Library")
library.config()
yield library
print("\nTeardown Library")
library = None
@pytest.fixture(scope="class")
def library_in_class(library_instance):
yield library_instance
class Test_Somemore:
@classmethod
def setup_class(cls):
print("\nSetup Class")
cls.library_instance.foo1()
@classmethod
def teardown_class(cls):
print("\nTeardown Class")
cls.library_instance.foo2()
@classmethod
def setup_method(cls, method):
print("\nSetup Test =", method.__name__)
cls.library_instance.foo3()
@classmethod
def teardown_method(cls, method):
print("\nTeardown Test =", method.__name__)
if method._outcome.errors:
cls.library_instance.foo4()
@pytest.mark.usefixtures("library_in_class")
@pytest.mark.asyncio
async def test_something_4(self):
print(f"\ntest 4 - {self.library_instance.var}")
assert 1 == 1
assert self.library_instance.var == 100
@pytest.mark.usefixtures("library_in_class")
@pytest.mark.asyncio
async def test_something_5(self):
print(f"\ntest 5 - {self.library_instance.var}")
assert 2 == 2
assert self.library_instance.var == 100
@pytest.mark.usefixtures("library_in_class")
@pytest.mark.asyncio
async def test_something_6(self):
print(f"\ntest 6 - {self.library_instance.var}")
assert 3 == 3
assert self.library_instance.var == 100
上述代码中,我添加了一个名为 library_in_class 的新的 fixture,用于在测试类中共享 library_instance。在 setup_class,teardown_class,setup_method 和 teardown_method 中,你可以直接使用 self.library_instance。在 teardown_method 中,我检查了测试是否失败,并根据需要调用了相应的函数。
英文:
I have a conftest.py:
import pytest
import asyncio
from some_library import MyLibrary
@pytest.fixture()
def event_loop(request):
loop = asyncio.get_event_loop_policy().new_event_loop()
yield loop
loop.close()
@pytest.fixture(name="library_instance", scope='session')
def fixture_library_instance():
library = MyLibrary()
print("\nSetup Library")
library.config()
yield library
print("\nTeardown Library")
library = None
And a test file (test_1.py):
import pytest
class Test_Somemore:
@classmethod
def setup_class(self):
print("\nSetup Class")
@classmethod
def teardown_class(self):
print("\nTeardown Class")
@classmethod
def setup_method(self, method):
print("\nSetup Test = ", method.__name__)
@classmethod
def teardown_method(self, method):
print("\nTeardown Test = ", method.__name__)
@pytest.mark.usefixtures("library_instance")
@pytest.mark.asyncio
async def test_something_4(self, library_instance):
print(f"\ntest 4 - {library_instance.var}")
assert 1 == 1
assert library_instance.var == 100
@pytest.mark.usefixtures("library_instance")
@pytest.mark.asyncio
async def test_something_5(self, library_instance):
print(f"\ntest 5 - {library_instance.var}")
assert 2 == 2
assert library_instance.var == 100
@pytest.mark.usefixtures("library_instance")
@pytest.mark.asyncio
async def test_something_6(self, library_instance):
print(f"\ntest 6 - {library_instance.var}")
assert 3 == 3
assert library_instance.var == 100
The order it is being called is:
- Setup Library
- Setup Class
- Setup Test (test 4)
- Teardown Test (test 4)
- Setup Test (test 5)
- Teardown Test (test 5)
- Setup Test (test 6)
- Teardown Test (test 6)
- Teardown Class
- Teardown Libary
This is ok.
What I need is the following:
- To have library_instance (from the fixture "fixture_library_instance") callable inside the setup_class, teardown_class, setup_method, and teardown_method. Not just the test cases. I haven't found a way to make this work.
- In teardown_method, check if the test has failed. If it did, I want to call some functions.
Basically something like this:
@classmethod
def setup_class(self):
print("\nSetup Class")
library_instance.foo1()
@classmethod
def teardown_class(self):
print("\nTeardown Class")
library_instance.foo2()
@classmethod
def setup_method(self, method):
print("\nSetup Test = ", method.__name__)
library_instance.foo3()
@classmethod
def teardown_method(self, method):
print("\nTeardown Test = ", method.__name__)
if test == FAIL:
library_instance.foo4()
Can somebody please help me?
答案1
得分: 1
你的要求都是可以实现的。
第一个要求(在setup方法中访问另一个fixture)如果你将你的setup/teardown方法改为fixtures的话,就会很容易。在这种情况下,你可以引用相同或更广泛范围的其他fixtures:
class TestSomemore:
@classmethod
@pytest.fixture(scope="class", autouse=True)
def prepare_class(cls, library_instance):
print("\nSetup Class")
library_instance.foo1()
yield
print("\nTeardown Class")
@pytest.fixture(autouse=True)
def prepare_method(self, request, library_instance):
print("\nSetup Test =", request.node.name)
library_instance.foo2()
yield
print("\nTeardown Test =", request.node.name)
一些备注:
- 我本可以保留魔术名称
setup_class
和setup_method
,但为了说明我将它们改变了。一旦你将它们变成fixtures,名称就不重要了。 - 为了自动调用fixtures,你必须设置
autouse=True
(这很明显,但我还是想提一下)。 - 像
setup_method
中传递method
参数是不会起作用的(它将被视为fixture名称),但你可以通过request
fixture 来获取名称。
使用fixture表示法可以说是比分开的setup/teardown方法更可取,因为它只需要一个方法,并且还允许在setup和teardown(在 yield
之前和之后)中使用相同的局部变量,尽管这也是品味的问题。
至于第二部分(检查fixture是否失败)- 这已经在这里很好地回答了,并附有链接到相关文档,所以我就不在这里重复了。
英文:
Both your requirements are possible.
The first one (accessing another fixture in a setup method) is trivial if you change your setup/teardown methods to fixtures. In this case, you can just reference other fixtures of the same or a wider scope:
class TestSomemore:
@classmethod
@pytest.fixture(scope="class", autouse=True)
def prepare_class(cls, library_instance):
print("\nSetup Class")
library_instance.foo1()
yield
print("\nTeardown Class")
@pytest.fixture(autouse=True)
def prepare_method(self, request, library_instance):
print("\nSetup Test = ", request.node.name)
library_instance.foo2()
yield
print("\nTeardown Test = ", request.node.name)
A few remarks:
- I could have retained the magic names
setup_class
andsetup_method
but changed them for illustration. As soon as you make them fixtures, the name does not matter. - In order to have the fixtures automatically called, you have to set
autouse=True
(quite obvious, but I wanted to mention it). - Passing the
method
argument as insetup_method
won't work (it will be seen as a fixture name), but you can get the name via therequest
fixture instead.
Using the fixture notation arguably is preferrable to separate setup/teardown methods, as it only needs one method, and also allows the use of the same local variables for both setup and teardown (e.g. before and after the yield
), though that is also a matter of taste.
As for the second part (checking if a fixture has failed) - this has been nicely answered here, with a link to the relevant documentation, so I won't repeat it here.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论