{"id":84335,"date":"2025-07-30T11:43:37","date_gmt":"2025-07-30T06:13:37","guid":{"rendered":"https:\/\/www.guvi.in\/blog\/?p=84335"},"modified":"2025-08-19T16:40:32","modified_gmt":"2025-08-19T11:10:32","slug":"page-object-model-pom-design-pattern","status":"publish","type":"post","link":"https:\/\/www.guvi.in\/blog\/page-object-model-pom-design-pattern\/","title":{"rendered":"Page Object Model (POM) Design Pattern with Python Selenium: A Complete Guide"},"content":{"rendered":"\n<p>In Selenium automation, as your test suite grows, maintaining scripts becomes challenging. Code duplication, fragile locators, and poor readability often slow down your team. That\u2019s where the <strong>Page Object Model (POM) design pattern<\/strong> comes in.<\/p>\n\n\n\n<p>In this guide, we\u2019ll explore how to implement Page Object Model in <strong>Python Selenium<\/strong>, why it\u2019s essential, and how it can improve your automation framework&#8217;s <strong>scalability, maintainability, and readability<\/strong>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>What is Page Object Model (POM)?<\/strong><\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1200\" height=\"630\" src=\"https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/01@2x-2-1200x630.png\" alt=\"What is Page Object Model (POM)?\" class=\"wp-image-85114\" srcset=\"https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/01@2x-2-1200x630.png 1200w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/01@2x-2-300x158.png 300w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/01@2x-2-768x403.png 768w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/01@2x-2-1536x806.png 1536w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/01@2x-2-2048x1075.png 2048w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/01@2x-2-150x79.png 150w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" title=\"\"><\/figure>\n\n\n\n<p><a href=\"https:\/\/www.guvi.in\/blog\/python-selenium-page-object-model-explained\/\" target=\"_blank\" rel=\"noreferrer noopener\">Page Object Model (POM)<\/a> is a design pattern that creates an object repository for web UI elements. Each web page is represented as a <strong>class<\/strong>, and its elements are defined as <strong>variables<\/strong>. All possible interactions (like click, input, and get text) are implemented as <strong>methods<\/strong> within that class.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Key Benefits of POM:<\/strong><\/h3>\n\n\n\n<ul>\n<li><strong>Separation of Concerns<\/strong>: Keeps locators and actions separate from test logic.<br><\/li>\n\n\n\n<li><strong>Improved Maintainability<\/strong>: Update locators in one place.<br><\/li>\n\n\n\n<li><strong>Code Reusability<\/strong>: Common actions can be reused across tests.<br><\/li>\n\n\n\n<li><strong>Better Readability<\/strong>: Tests are more readable and closer to business logic.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Folder Structure for POM&nbsp;<\/strong><\/h2>\n\n\n\n<p>A clean directory structure is crucial for POM. Here&#8217;s a typical structure:<\/p>\n\n\n\n<p>\ud83d\udce6 project-root\/<\/p>\n\n\n\n<p>\u251c\u2500\u2500 \ud83d\udcc1 <strong>tests\/<\/strong><\/p>\n\n\n\n<p>\u2502<strong> &nbsp; <\/strong>\u251c\u2500\u2500 \ud83d\udcdd __ init __.py &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # Empty init file<\/p>\n\n\n\n<p>\u2502 &nbsp; \u2514\u2500\u2500 \ud83d\udcdd test_login.py&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # Test cases using Page Objects<\/p>\n\n\n\n<p>\u2502<\/p>\n\n\n\n<p>\u251c\u2500\u2500 \ud83d\udcc1 <strong>pages\/<\/strong><\/p>\n\n\n\n<p>\u2502<strong> &nbsp; <\/strong>\u251c\u2500\u2500 \ud83d\udcdd __ init __.py &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # Empty init file<\/p>\n\n\n\n<p>\u2502 &nbsp; \u251c\u2500\u2500 \ud83d\udcdd login_page.py&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # Page Object for Login Page<\/p>\n\n\n\n<p>\u2502 &nbsp; \u2514\u2500\u2500 \ud83d\udcdd home_page.py &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # Page Object for Home Page<\/p>\n\n\n\n<p>\u2502<\/p>\n\n\n\n<p>\u251c\u2500\u2500 \ud83d\udcc1<strong> utils\/<\/strong><\/p>\n\n\n\n<p>\u2502<strong> &nbsp; <\/strong>\u251c\u2500\u2500 \ud83d\udcdd __ init __.py &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # Empty init file<\/p>\n\n\n\n<p>\u2502 &nbsp; \u251c\u2500\u2500 \ud83d\udcdd driver_factory.py &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # Browser driver setup &amp; teardown<\/p>\n\n\n\n<p>\u2502 &nbsp; \u2514\u2500\u2500 \ud83d\udcdd config.py &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # Configurations (URLs, credentials)<\/p>\n\n\n\n<p>\u2502<\/p>\n\n\n\n<p>\u251c\u2500\u2500 \ud83d\udcc1 <strong>reports\/<\/strong><\/p>\n\n\n\n<p>\u2502 &nbsp; \u251c\u2500\u2500 \ud83d\udcc1 pytest_html\/&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # HTML report results<\/p>\n\n\n\n<p>\u2502 &nbsp; \u2514\u2500\u2500 \ud83d\udcc1 screenshots\/ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # Screenshots for failed tests<\/p>\n\n\n\n<p>\u2502<\/p>\n\n\n\n<p>\u2514\u2500\u2500 \ud83d\udcdd requirements.txt &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # Python dependencies<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Implementing POM in Python Selenium<\/strong><\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1200\" height=\"630\" src=\"https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/02@2x-2-1200x630.png\" alt=\"Implementing POM in Python Selenium\" class=\"wp-image-85115\" srcset=\"https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/02@2x-2-1200x630.png 1200w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/02@2x-2-300x158.png 300w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/02@2x-2-768x403.png 768w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/02@2x-2-1536x806.png 1536w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/02@2x-2-2048x1075.png 2048w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/02@2x-2-150x79.png 150w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" title=\"\"><\/figure>\n\n\n\n<p>Let\u2019s walk through an example of automating <strong>Amazon Login<\/strong> using POM.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 1: Install Required Packages<\/strong><\/h3>\n\n\n\n<p><code>pip install selenium pytest<\/code><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 2: Driver Setup (driver_factory.py)<\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>from selenium import webdriver\n\nclass DriverFactory:\n\n&nbsp;&nbsp;&nbsp;&nbsp;@staticmethod\n\n&nbsp;&nbsp;&nbsp;&nbsp;def get_driver():\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;driver = webdriver.Chrome()\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;driver.maximize_window()\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;driver.implicitly_wait(10)\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return driver<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 3: Create Page Classes<\/strong><\/h3>\n\n\n\n<p><strong>login_page.py<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>from selenium.webdriver.common.by import By\n\nclass LoginPage:\n\n&nbsp;&nbsp;&nbsp;&nbsp;def __init__(self, driver):\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.driver = driver\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.sign_in_link = (By.ID, \"nav-link-accountList\")\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.email_field = (By.ID, \"ap_email\")\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.continue_button = (By.ID, \"continue\")\n\n&nbsp;&nbsp;&nbsp;&nbsp;def click_sign_in(self):\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.driver.find_element(*self.sign_in_link).click()\n\n&nbsp;&nbsp;&nbsp;&nbsp;def enter_email(self, email):\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.driver.find_element(*self.email_field).send_keys(email)\n\n&nbsp;&nbsp;&nbsp;&nbsp;def click_continue(self):\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.driver.find_element(*self.continue_button).click()<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 4: Write Test Script (test_login.py)<\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>import pytest\n\nfrom pages.login_page import LoginPage\n\nfrom utils.driver_factory import DriverFactory\n\nclass TestLogin:\n\n&nbsp;&nbsp;&nbsp;&nbsp;def setup_method(self):\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.driver = DriverFactory.get_driver()\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.driver.get(\"https:\/\/www.amazon.com\")\n\n&nbsp;&nbsp;&nbsp;&nbsp;def teardown_method(self):\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.driver.quit()\n\n&nbsp;&nbsp;&nbsp;&nbsp;def test_login_with_valid_email(self):\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;login_page = LoginPage(self.driver)\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;login_page.click_sign_in()\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;login_page.enter_email(\"testuser@example.com\")\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;login_page.click_continue()\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert \"Authentication\" in self.driver.title&nbsp; # Example assertion<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 5: Running the Tests<\/strong><\/h3>\n\n\n\n<p><code>pytest tests\/test_login.py<\/code><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 6: Advanced Enhancements<\/strong><\/h3>\n\n\n\n<ul>\n<li><strong>BasePage Class<\/strong>: For common actions like click(), send_keys(), get_text().<br><\/li>\n\n\n\n<li><strong>PageFactory Pattern<\/strong>: To lazily initialize web elements.<br><\/li>\n\n\n\n<li><strong>Logging &amp; Reporting<\/strong>: Integrate <a href=\"https:\/\/pytest-html.readthedocs.io\/en\/latest\/user_guide.html\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">Pytest HTML Reports.<\/a><br><\/li>\n\n\n\n<li><strong>Environment Config<\/strong>: Manage URLs, credentials via config files.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Best Practices for POM in Python Selenium<\/strong><\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1200\" height=\"630\" src=\"https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/03@2x-1-1200x630.png\" alt=\"Best Practices for POM in Python Selenium\" class=\"wp-image-85117\" srcset=\"https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/03@2x-1-1200x630.png 1200w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/03@2x-1-300x158.png 300w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/03@2x-1-768x403.png 768w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/03@2x-1-1536x806.png 1536w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/03@2x-1-2048x1075.png 2048w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/08\/03@2x-1-150x79.png 150w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" title=\"\"><\/figure>\n\n\n\n<ul>\n<li>Follow SRP (Single Responsibility Principle) \u2014 one page, one class.<\/li>\n\n\n\n<li>Avoid hardcoding locators and data.<\/li>\n\n\n\n<li>Implement proper waits instead of time.sleep().<\/li>\n\n\n\n<li>Modularize common utilities (driver setup, waits, screenshots).<\/li>\n\n\n\n<li>Keep test assertions in test scripts, not in page objects.<\/li>\n<\/ul>\n\n\n\n<p>In case you want to learn more about Python Selenium in Automation Testing, consider enrolling for GUVI\u2019s&nbsp;<a href=\"https:\/\/www.guvi.in\/zen-class\/selenium-automation-testing-course\/\" target=\"_blank\" rel=\"noreferrer noopener\"><\/a><a href=\"https:\/\/www.guvi.in\/zen-class\/selenium-automation-testing-course\/?utm_source=blog&amp;utm_medium=hyperlink&amp;utm_campaign=page-object-model\" target=\"_blank\" rel=\"noreferrer noopener\">Selenium Automation Testing Course<\/a>,&nbsp;which teaches you everything from scratch by providing an industry-grade certificate!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Conclusion<\/strong><\/h2>\n\n\n\n<p>The <strong>Page Object Model<\/strong> is a must-have design pattern for any robust Selenium automation framework. It helps you write <strong>clean, maintainable, and scalable<\/strong> test code in Python.<\/p>\n\n\n\n<p>By adopting POM, you not only reduce technical debt but also create a foundation for advanced practices like <strong>Data-Driven Testing, CI\/CD Integration, and Parallel Execution<\/strong>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In Selenium automation, as your test suite grows, maintaining scripts becomes challenging. Code duplication, fragile locators, and poor readability often slow down your team. That\u2019s where the Page Object Model (POM) design pattern comes in. In this guide, we\u2019ll explore how to implement Page Object Model in Python Selenium, why it\u2019s essential, and how it [&hellip;]<\/p>\n","protected":false},"author":48,"featured_media":85113,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[40,706],"tags":[],"views":"3011","authorinfo":{"name":"Basil Ahamed","url":"https:\/\/www.guvi.in\/blog\/author\/basil-ahamed-s\/"},"thumbnailURL":"https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/07\/Page-Object-Model-POM-Design-Pattern-with-Python-Selenium_-300x116.png","jetpack_featured_media_url":"https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/07\/Page-Object-Model-POM-Design-Pattern-with-Python-Selenium_.png","_links":{"self":[{"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/posts\/84335"}],"collection":[{"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/users\/48"}],"replies":[{"embeddable":true,"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/comments?post=84335"}],"version-history":[{"count":8,"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/posts\/84335\/revisions"}],"predecessor-version":[{"id":85118,"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/posts\/84335\/revisions\/85118"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/media\/85113"}],"wp:attachment":[{"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/media?parent=84335"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/categories?post=84335"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/tags?post=84335"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}