将参数传递给 pytest fixture 以进行拆卸
pass a parameter to a pytest fixture for teardown
问题:
清理从测试中创建的测试工件。在下面的例子中,如何使用 pytest fixture 从数据库中删除在测试期间创建的单个行? (并不是每 运行 之后都应该从 table 中删除所有内容。否则可以使用删除所有行或删除 table。创建行的行标识符在测试时保存在一个函数变量中。
是否可以将测试期间创建的变量作为参数传递到 pytest 中的夹具中? fixture 需要始终 运行 测试是通过失败还是成功完成的。在测试 运行 之前,行标识符是未知的。
用夹具说明的问题
@pytest.fixture()
def clean_up_db_row(row_id):
yield
delete_from_db(self.row_id). # code to delete the row based on the id
def test_something_added_to_database(clean_up_db_row):
row_id = create_db_row() # function under test
...
assert row_id in db # test that information added to the database
# the clean_up_db_row fixture will always run but how will it know about the id variable defined in the function?
如果断言在测试中途失败,则在清理到最后时不会删除测试期间添加的行。因为测试停止执行。
问题示例是没有 pytest 夹具:
def clean_up_db_row(row_id):
yield
delete_from_db(row_id). # code to delete the row based on the id
def test_something_added_to_database():
row_id = create_db_row() # function under test
...
assert row_id in db # test that information added to the database
clean_up_db_row(row_id) # this won’t run if there is a failure
没有 pytest fixture 的解决方案
def clean_up_db_row(row_id):
yield
delete_from_db(row_id). # code to delete the row based on the id
def test_something_added_to_database():
row_id = create_db_row() # function under test
...
try:
assert row_id in db # test that information added to the database
except Exception as e:
raise e
finally:
clean_up_db_row(row_id) # this will always run but doesn’t use a fixture
在 class
上使用实例变量的潜在解决方案
class TestCaseCleanUp:
@pytest.fixture(autouse=True)
def clean_up_db_row(self):
yield
delete_from_db(self.row_id). # code to delete the row based on the id
def test_something_added_to_database(self):
self.row_id = create_db_row() # function under test
...
assert self.row_id in db # test that information added to the database
# the autouse fixture can use the self.row_id assigned
fixture 产生的对象被运行器注入到测试上下文中。这可以是你想要的任何对象,测试可以自由改变它。
这是一个适合您的模式:
@pytest.fixture()
def clean_up_db_rows():
row_ids = []
yield row_ids
for row_id in row_ids:
delete_from_db(row_id)
def test_something_added_to_database(clean_up_db_rows):
row_id = create_db_row() # function under test
clean_up_db_rows.append(row_id)
...
assert row_id in db # test that information added to the database
我找到了另一个解决方案here:
Create a class in conftest.py and import it in your test module. To protect yourself from errors caused by failed testcases that were suppose to add values in the class, assign None to all the known values.
conftest.py:
class ValueStorage:
value1 = None
value2 = None
test_mytest.py:
from conftest import ValueStorage
def test_one():
ValueStorage.value1 = "anything you want here"
def test_two():
assert ValueStorage.value1 == "anything you want here"
ValueStorage.value2 = ValueStorage.value1
class TestClass:
def test_three(self):
assert ValueStorage.value1 == ValueStorage.value2
You can pass dictionaries and lists and anything you feel like. If you require persistence (want the values to be kept from one run to another you can write them in a json file or use the cache option)
问题: 清理从测试中创建的测试工件。在下面的例子中,如何使用 pytest fixture 从数据库中删除在测试期间创建的单个行? (并不是每 运行 之后都应该从 table 中删除所有内容。否则可以使用删除所有行或删除 table。创建行的行标识符在测试时保存在一个函数变量中。
是否可以将测试期间创建的变量作为参数传递到 pytest 中的夹具中? fixture 需要始终 运行 测试是通过失败还是成功完成的。在测试 运行 之前,行标识符是未知的。
用夹具说明的问题
@pytest.fixture()
def clean_up_db_row(row_id):
yield
delete_from_db(self.row_id). # code to delete the row based on the id
def test_something_added_to_database(clean_up_db_row):
row_id = create_db_row() # function under test
...
assert row_id in db # test that information added to the database
# the clean_up_db_row fixture will always run but how will it know about the id variable defined in the function?
如果断言在测试中途失败,则在清理到最后时不会删除测试期间添加的行。因为测试停止执行。
问题示例是没有 pytest 夹具:
def clean_up_db_row(row_id):
yield
delete_from_db(row_id). # code to delete the row based on the id
def test_something_added_to_database():
row_id = create_db_row() # function under test
...
assert row_id in db # test that information added to the database
clean_up_db_row(row_id) # this won’t run if there is a failure
没有 pytest fixture 的解决方案
def clean_up_db_row(row_id):
yield
delete_from_db(row_id). # code to delete the row based on the id
def test_something_added_to_database():
row_id = create_db_row() # function under test
...
try:
assert row_id in db # test that information added to the database
except Exception as e:
raise e
finally:
clean_up_db_row(row_id) # this will always run but doesn’t use a fixture
在 class
上使用实例变量的潜在解决方案class TestCaseCleanUp:
@pytest.fixture(autouse=True)
def clean_up_db_row(self):
yield
delete_from_db(self.row_id). # code to delete the row based on the id
def test_something_added_to_database(self):
self.row_id = create_db_row() # function under test
...
assert self.row_id in db # test that information added to the database
# the autouse fixture can use the self.row_id assigned
fixture 产生的对象被运行器注入到测试上下文中。这可以是你想要的任何对象,测试可以自由改变它。
这是一个适合您的模式:
@pytest.fixture()
def clean_up_db_rows():
row_ids = []
yield row_ids
for row_id in row_ids:
delete_from_db(row_id)
def test_something_added_to_database(clean_up_db_rows):
row_id = create_db_row() # function under test
clean_up_db_rows.append(row_id)
...
assert row_id in db # test that information added to the database
我找到了另一个解决方案here:
Create a class in conftest.py and import it in your test module. To protect yourself from errors caused by failed testcases that were suppose to add values in the class, assign None to all the known values.
conftest.py:
class ValueStorage:
value1 = None
value2 = None
test_mytest.py:
from conftest import ValueStorage
def test_one():
ValueStorage.value1 = "anything you want here"
def test_two():
assert ValueStorage.value1 == "anything you want here"
ValueStorage.value2 = ValueStorage.value1
class TestClass:
def test_three(self):
assert ValueStorage.value1 == ValueStorage.value2
You can pass dictionaries and lists and anything you feel like. If you require persistence (want the values to be kept from one run to another you can write them in a json file or use the cache option)