为什么 pytest fixture 和直接调用的函数产生的值不同?
Why are the values yielded by a pytest fixture and a function called directly different?
在下面的代码中,我得到的是一个生成器对象
<generator object a at 0x7feb40b2d7b0>
from playwright.sync_api import sync_playwright
def get_playwright():
with sync_playwright() as playwright:
yield playwright
print(get_playwright())
但是当我使用pytest时,我得到的是一个class对象
<class 'playwright.sync_api._generated.Playwright'>`:
# conftest.py
import pytest
from playwright.sync_api import sync_playwright
@pytest.fixture()
def get_playwright():
with sync_playwright() as playwright:
yield playwright
# test_one.py
def test(get_playwright):
print(get_playwright)
我想知道为什么会这样?如何在不使用 pytest 的情况下获得 class?
对于第一种形式:
def get_playwright():
with sync_playwright() as playwright:
yield playwright
print(get_playwright()) # <generator object get_playwright at 0x108aac580>
这是预期的,因为 get_playwright
是 generator, which returns a generator iterator, which you have to call next(...)
从迭代器获取每个产生的值。
考虑一个更简单的 non-playwright 示例:
In [14]: def generate_nums():
...: for num in range(10):
...: yield num
...:
In [15]: nums = generate_nums()
In [16]: nums
Out[16]: <generator object generate_nums at 0x11115e6d0>
In [17]: next(nums)
Out[17]: 0
In [18]: next(nums)
Out[18]: 1
In [19]: next(nums)
Out[19]: 2
有关更多示例,请参阅 Understanding generators in Python。
由于你的 get_playwright
returns 是一个迭代器,你需要调用 next()
一次 来获取实际对象:
from playwright.sync_api import sync_playwright
def get_playwright():
with sync_playwright() as playwright:
yield playwright
playwright_generator = get_playwright()
print(playwright_generator) # <generator object get_playwright at 0x104031580>
playwright = next(playwright_generator)
print(playwright) # <playwright._impl._playwright.Playwright object at 0x1041aabb0>
对于第二种形式:
@pytest.fixture()
def get_playwright():
with sync_playwright() as playwright:
yield playwright
def test(get_playwright):
print(get_playwright)
应该是一样的情况,但是只是如果pytest是一个生成器,它会自动调用next()
fixture值。我无法从 pytest 文档中找到有关此行为的文档,但其中一位 pytest 作者提到了's/maintainer's :
Here's roughly the execution here
- pytest notices your fixture is used for the test function
- pytest calls the fixture function
- since it is a generator, it returns immediately without executing code
- pytest notices it is a generator, calls
next(...)
on it
- this causes the code to execute until the
yield
and then "pausing". you can think of it kind of as a co-routine
...
- pytest then executes your test function
...这可能就是为什么传递给测试函数的值已经是 next
-ed 值,剧作家对象。
在下面的代码中,我得到的是一个生成器对象
<generator object a at 0x7feb40b2d7b0>
from playwright.sync_api import sync_playwright
def get_playwright():
with sync_playwright() as playwright:
yield playwright
print(get_playwright())
但是当我使用pytest时,我得到的是一个class对象
<class 'playwright.sync_api._generated.Playwright'>`:
# conftest.py
import pytest
from playwright.sync_api import sync_playwright
@pytest.fixture()
def get_playwright():
with sync_playwright() as playwright:
yield playwright
# test_one.py
def test(get_playwright):
print(get_playwright)
我想知道为什么会这样?如何在不使用 pytest 的情况下获得 class?
对于第一种形式:
def get_playwright():
with sync_playwright() as playwright:
yield playwright
print(get_playwright()) # <generator object get_playwright at 0x108aac580>
这是预期的,因为 get_playwright
是 generator, which returns a generator iterator, which you have to call next(...)
从迭代器获取每个产生的值。
考虑一个更简单的 non-playwright 示例:
In [14]: def generate_nums():
...: for num in range(10):
...: yield num
...:
In [15]: nums = generate_nums()
In [16]: nums
Out[16]: <generator object generate_nums at 0x11115e6d0>
In [17]: next(nums)
Out[17]: 0
In [18]: next(nums)
Out[18]: 1
In [19]: next(nums)
Out[19]: 2
有关更多示例,请参阅 Understanding generators in Python。
由于你的 get_playwright
returns 是一个迭代器,你需要调用 next()
一次 来获取实际对象:
from playwright.sync_api import sync_playwright
def get_playwright():
with sync_playwright() as playwright:
yield playwright
playwright_generator = get_playwright()
print(playwright_generator) # <generator object get_playwright at 0x104031580>
playwright = next(playwright_generator)
print(playwright) # <playwright._impl._playwright.Playwright object at 0x1041aabb0>
对于第二种形式:
@pytest.fixture()
def get_playwright():
with sync_playwright() as playwright:
yield playwright
def test(get_playwright):
print(get_playwright)
应该是一样的情况,但是只是如果pytest是一个生成器,它会自动调用next()
fixture值。我无法从 pytest 文档中找到有关此行为的文档,但其中一位 pytest 作者提到了's/maintainer's
Here's roughly the execution here
- pytest notices your fixture is used for the test function
- pytest calls the fixture function
- since it is a generator, it returns immediately without executing code
- pytest notices it is a generator, calls
next(...)
on it
- this causes the code to execute until the
yield
and then "pausing". you can think of it kind of as a co-routine ...- pytest then executes your test function
...这可能就是为什么传递给测试函数的值已经是 next
-ed 值,剧作家对象。