本文共 4110 字,大约阅读时间需要 13 分钟。
Pytest fixture是一种强大的工具,广泛应用于测试场景下的资源管理和环境准备工作。然而,尽管其功能强大, fixture 函数在实际应用中也存在一些潜在的问题。通过本文,我们将深入探讨这些问题,并提出相应的优化方案。
在使用 Pytest fixture 的过程中,最常见的问题是其不可靠性,主要体现在以下几个方面:
Fixture 函数名称缺乏描述性
例如,命名为setup 的 fixture 函数,虽然简洁,但并未能明确表达其具体功能,导致维护和阅读难度增加。Fixture 函数操作复杂
如果一个 fixture 函数包含多个操作步骤,尤其是涉及资源创建和管理的操作,往往会导致代码冗余,难以复用。Yield 之前的操作一旦出错,teardown 就不会执行
这是最严重的问题之一。例如,如果在yield 之前创建的资源未能正确生成,teardown 操作就不会执行,导致资源未能被清理,进而引发后续测试用例的异常。为了解决上述问题,我们可以采取以下优化措施:
以下是一个经典的优化示例,展示了如何将复杂操作分解为多个独立的 fixture 函数:
import pytestfrom emaillib import Email, MailAdminClient@pytest.fixturedef mail_admin(): return MailAdminClient()@pytest.fixturedef sending_user(mail_admin): user = mail_admin.create_user() yield user mail_admin.delete_user(user)@pytest.fixturedef receiving_user(mail_admin): user = mail_admin.create_user() yield user mail_admin.delete_user(user)def test_email_received(receiving_user, email): email = Email(subject="Hey!", body="How's it going?") sending_user.send_email(email, receiving_user) assert email in receiving_user.inbox
优化说明:
mail_admin 只负责创建管理员客户端。teardown 操作通过 yield 之后的清理代码自动执行,避免因错误导致资源未能清理。以下是一个 Web 自动化测试的优化示例,展示了如何在复杂场景中实现 fixture 函数的高效管理:
from uuid import uuid4from urllib.parse import urljoinfrom selenium.webdriver import Chromeimport pytestfrom src.utils.pages import LoginPage, LandingPagefrom src.utils import AdminApiClientfrom src.utils.data_types import User@pytest.fixturedef admin_client(base_url, admin_credentials): return AdminApiClient(base_url, **admin_credentials)@pytest.fixturedef user(admin_client): _user = User(name="Susan", username=f"testuser-{uuid4()}", password="P4$$word") admin_client.create_user(_user) yield _user admin_client.delete_user(_user)@pytest.fixturedef driver(): _driver = Chrome() yield _driver _driver.quit()@pytest.fixturedef login(driver, base_url, user): driver.get(urljoin(base_url, "/login")) page = LoginPage(driver) page.login(user)@pytest.fixturedef landing_page(driver, login): return LandingPage(driver)def test_name_on_landing_page_after_login(landing_page, user): assert landing_page.header == f"Welcome, {user.name}!" 优化说明:
admin_client 和 user fixture 函数通过参数传递,实现了资源的灵活管理。driver fixture 函数负责浏览器的启动与退出,确保测试环境的清理。以下是基于实际项目中的优化示例,展示了如何在复杂场景中实现 fixture 函数的高效管理:
@pytest.fixturedef insert_sm_purchase_order(): """插入采购订单表的数据""" db = DB("db_info") purchase_order_sn = "CGN016" + deal_date() + str(random_int(4)) purchase_order_id = db.get_table_usable_latest_id("tcwms", "sm_purchase_order") insert_sql = """INSERT INTO `tcw` ...""" db.exec_sql(insert_sql) db.close() yield purchase_order_id, purchase_order_sn db = DB("db_info") db.exec_sql("DELETE FROM `tcw` ...") db.close()@pytest.fixturedef insert_sm_purchase_order_goods(insert_sm_purchase_order): """插入采购商品表的数据""" db = DB("db_info") purchase_order_goods_id = db.get_table_usable_latest_id("tcwms", "sm_purchase_order_goods") po_id = insert_sm_purchase_order[0] purchase_order_sn = insert_sm_purchase_order[1] insert_sql = """INSERT INTO `tcw` ...""" db.exec_sql(insert_sql) db.close() yield purchase_order_goods_id, po_id, purchase_order_sn db = DB("tcwms_db_info") db.exec_sql("DELETE FROM `tcw` ...") db.close() 优化说明:
insert_sm_purchase_order 和 insert_sm_purchase_order_goods 分别负责主表和附属表的数据插入。teardown 操作通过 yield 之后的清理代码自动执行,确保数据的完整性。为了更直观地理解 fixture 函数的优化效果,我们可以设计以下测试场景:
Fixture2 报错的情况
insert_sm_purchase_order_goods 在插入数据时发生错误,insert_sm_purchase_order 也会停止执行,避免数据不一致的问题。Fixture1 报错的情况
insert_sm_purchase_order 在插入数据时发生错误,整个测试场景会自动回滚,确保环境不受污染。通过对 Pytest fixture 的深入分析,本文揭示了 fixture 函数在实际应用中的潜在问题,并提出了相应的优化方案。通过将复杂操作分解为多个独立的 fixture 函数,实现了资源管理的透明性和可靠性。同时,通过合理的测试场景设计,验证了优化效果的有效性。在实际项目中,可以根据具体需求继续对 fixture 函数进行优化和扩展,以满足更复杂的测试场景需求。
转载地址:http://gkkfz.baihongyu.com/