AttributeError: module 'pages' has no attribute 'home_page'

AttributeError: module 'pages' has no attribute 'home_page'

我有一个 BasePage

from selenium import webdriver
from selenium.webdriver import ActionChains, DesiredCapabilities
import pages

"""This class is the parent of all pages"""
"""It contains all the generic methods and utilities for all pages"""

class BasePage:

    KV_HUB_URL = "Selenium_Grid_Hub"
    KV_PLATFORM = "Platform"
    KV_BROWSER = "Browser"
    KV_BASE_URL = "Base_Url"

    """If the page is passed with the driver, config, save the info. This should be created from another page object"""
    def __init__(self, driver, config):
        self.__driver = driver
        self.__config = config

    #https://www.selenium.dev/selenium/docs/api/py/webdriver/selenium.webdriver.common.desired_capabilities.html
    """If the page is created with the configuration file, set up a new web driver"""
    def __init__(self, config):
        self.__config = config
        capabilities = DesiredCapabilities()
        if config[self.KV_BROWSER] == "CHROME":
            capabilities = DesiredCapabilities.CHROME.copy()
        elif config[self.KV_BROWSER] == "FIREFOX":
            capabilities.FIREFOX = DesiredCapabilities.FIREFOX.copy()
        capabilities['platform'] = config[self.KV_PLATFORM]
        self.__driver = webdriver.Remote(
            desired_capabilities=capabilities,
            command_executor=config[self.KV_HUB_URL])

    def close(self):
        self.__driver.close()

    def gotoHomePage(self):
        self.__driver.get(self.__config[self.KV_BASE_URL])
        return pages.home_page.HomePage(self, self.__driver, self.__config)

我也有主页

from selenium.webdriver.common.by import By
import pages

class HomePage(pages.base_page.BasePage):

    SEARCH_BAR = (By.XPATH, "//form[@role='search']")
    SEARCH_INPUT = (By.XPATH, "//input[@name='q']")

    def is_search_bar_dislayed(self):
        return False

为了不运行进入循环导入,我只进行了“导入页面” 但是,当我 运行,在 BasePage 的 gotoHomePage 中,行

return pages.home_page.HomePage(self, self.__driver, self.__config)

回来了

AttributeError: module 'pages' has no attribute 'home_page'

你能告诉我这是什么意思以及如何解决吗?

需要解决的主要问题是您的 class 继承设计。但首先,让我们解决当前代码的需求。假设这是你的文件结构:

.
└── pages
    ├── base_page.py
    └── home_page.py

解决方案 1:

添加pages/__init__.py,内容如下:

import pages.base_page
import pages.home_page

解决方案 2:

更改您的 base_page.py 以显式导入 pages.home_page 而不仅仅是 pages:

class BasePage:
    ...
    def gotoHomePage(self):
        import pages.home_page
        ...
        return pages.home_page.HomePage(self.__driver, self.__config)

解决方案 3:

将您的 base_page.py 更改为导入 pages.home_page.HomePage:

class BasePage:
    ...
    def gotoHomePage(self):
        from pages.home_page import HomePage
        ...
        return HomePage(self.__driver, self.__config)

以上所有都会有一个成功的输出:

>>> from pages.base_page import BasePage
>>> BasePage("some", "thing").gotoHomePage()
<pages.home_page.HomePage object at 0x7f7bb8dbcd30>
>>> 
>>> import pages.base_page
>>> pages.base_page.BasePage("some", "thing").gotoHomePage()
<pages.home_page.HomePage object at 0x7f7bb8cc7bb0>

正如我之前所说,主要问题是class继承“is-a”的关系。 HomePage is-a BasePage,在某种程度上,如果您创建 HomePage 的新实例,您基本上创建了一个 BasePage。由于这个原因,BasePage.gotoHomePage() 是错误的,因为创建一个可能已经与您的类型相同的新页面似乎不合适(如果当前实例是 HomePage),这就像在告诉“嘿gotoHomePage请创造一个新的我。

您可能想要重新设计此方法。这是使用 Factory Design Pattern.

的解决方案

page_factory.py

from abc import ABC, abstractmethod

from pages.base_page import BasePage
from pages.home_page import HomePage


class PageFactory(ABC):
    @abstractmethod
    def create_page(self, *args, **kwargs) -> BasePage:
        raise NotImplementedError()


class HomePageCreator(PageFactory):
    def create_page(self, driver, config) -> BasePage:
        return HomePage(driver, config)

或者如果你想要一个简化版本:

page_factory.py

from pages.home_page import HomePage

class SimplifiedPageFactory(ABC):
    def create_home_page(self, driver, config) -> HomePage:
        return HomePage(driver, config)

输出:

>>> from pages.page_factory import HomePageCreator, SimplifiedPageFactory
>>> 
>>> HomePageCreator().create_page("something", "anything")
<pages.home_page.HomePage object at 0x7fbfbc118ca0>
>>> 
>>> SimplifiedPageFactory().create_home_page("something", "anything")
<pages.home_page.HomePage object at 0x7fbfbc1b5040>

然后,导入语句的依赖顺序将严格为 child -> parent,因此在您的情况下为 home_page.py -> base_page.py,因此不再存在循环依赖问题。现在,您始终可以在所有 child class 中执行 from pages.base_page import BasePage,例如 home_page.py。这也与您在 base_page.py 中陈述的

的计划一致

"This class is the parent of all pages"

这意味着它应该是一个独立的模块,不依赖于其他模块,从而避免循环依赖。