Python中的页面对象模式循环导入问题

Posted

技术标签:

【中文标题】Python中的页面对象模式循环导入问题【英文标题】:Page Object Pattern Circular import problem in Python 【发布时间】:2022-01-22 18:10:39 【问题描述】:

我正在使用页面对象模式编写我的自动化框架,并且在实现视图类时遇到了这个错误。我已将这些类放在单独的模块中,我希望它们保持分离。问题是我希望两个类中的实例方法在执行某些 UI 操作时返回另一个类的对象。

有没有办法在将这些类放在单独的模块中时修复循环错误?

cart_page.py

from pages.base_page import BasePage
from utils.locators import CartLocators
from pages.main_page import MainPage

class CartPage(BasePage):
    def __init__(self, driver):
        self.locators = CartLocators()
        super().__init__(driver, 'https://www.saucedemo.com/cart.html')

    def click_continue_shopping(self):
        self.find_element(*self.locators.CONTINUE_SHOPPING_BTN).click()
        return MainPage(self.driver)

ma​​in_page.py

from pages.base_page import BasePage
from utils.locators import MainPageHeaderLocators, MainPageItemListLocators, InventoryItemLocators
from pages.cart_page import CartPage

class MainPage(BasePage):
    def __init__(self, driver):
        super().__init__(driver, "https://www.saucedemo.com/invetory.html")
        self.header = MainPageHeader(self.driver)
        self.item_list = MainPageItemList(self.driver)
        self.inventory_item = InventoryItemPage(self.driver)

    def open_cart(self):
        self.header.open_cart()
        return CartPage(self.driver)
E   ImportError: cannot import name 'MainPage' from partially initialized module 'pages.main_page' (most likely due to a circular import) (/Users/marcin94/PycharmProjects/sauce_demo_ui_tests/pages/main_page.py)

【问题讨论】:

您始终可以在 cart_page.pyclick_continue_shopping() 函数中导入 MainPage。这将摆脱循环依赖。 通常你只需要在MainPage中写一些常用的函数,我猜open_cart()是做一些特殊的事情 @saquintes 你觉得这个解决方案够干净吗? 这可能是一个见仁见智的问题。当我必须绕过循环依赖时,我自己已经完成了。 import <...> 的代码在已经导入时非常有效。但是,如果我可以重新组织事物的组织方式以完全避免依赖,那是我的偏好。但有时它就是不成功。 【参考方案1】:

不要使用from。直接导入模块:

cart_page.py

from pages.base_page import BasePage
from utils.locators import CartLocators
import pages.main_page

class CartPage(BasePage):
    def __init__(self, driver):
        self.locators = CartLocators()
        super().__init__(driver, 'https://www.saucedemo.com/cart.html')

    def click_continue_shopping(self):
        self.find_element(*self.locators.CONTINUE_SHOPPING_BTN).click()
        return pages.main_page.MainPage(self.driver)

ma​​in_page.py

from pages.base_page import BasePage
from utils.locators import MainPageHeaderLocators, MainPageItemListLocators, InventoryItemLocators
import pages.cart_page

class MainPage(BasePage):
    def __init__(self, driver):
        super().__init__(driver, "https://www.saucedemo.com/invetory.html")
        self.header = MainPageHeader(self.driver)
        self.item_list = MainPageItemList(self.driver)
        self.inventory_item = InventoryItemPage(self.driver)

    def open_cart(self):
        self.header.open_cart()
        return pages.cart_page.CartPage(self.driver)

【讨论】:

嗯,我想就是这样。仍在试图弄清楚圆形实际上是如何出现的。 它们出现在您尝试导入 A 时,然后在页面顶部,A 尝试导入 B,然后在页面顶部 B 尝试导入 A。如果有效,它有效,但我看不出这个答案如何解决问题。我希望它仍然会导致循环依赖问题。 @saquintes 因为 Python 会跟踪所有“已加载”的模块。因此,当您在第二个模块中导入第一个模块时,Python 将其识别为已加载,因此它会保存对它的引用并继续运行。

以上是关于Python中的页面对象模式循环导入问题的主要内容,如果未能解决你的问题,请参考以下文章

Python中的循环依赖

如何正确处理 Python 中的循环模块依赖关系?

(转)Python中的模块循环导入问题

Python中的循环模块依赖和相对导入

Python中的循环导入依赖

Python中的单例模式