1
\$\begingroup\$

I was trying to create the selenium web element object repository in python. I have come up with three ways to do so. However, I am new to python so I am not sure which one is better than other.

Note: I am using Page object pattern for writing my tests, however just for understanding and simplicity I have put all the function in one file (class).

First: Using Decorator

def FindBy(by, value):
    def decorator(func):
        def wrapper(self):
            return self.driver.find_element(by, value)
        return wrapper
    return decorator


class TestGoogle(object):

    @FindBy(By.NAME, "q")
    def search_input(self): pass

    def test_search(self):
        self.driver = webdriver.Firefox()
        self.driver.get("https://google.com")
        self.search_input().send_keys("selenium python")

Second & Third: using Lambda and Method

class TestGoogle(object):

    def find_element(self, by, value):
        return self.driver.find_element(by, value)

    def search_input(self): return self.find_element(By.NAME, "q")

    search_input_1 = lambda self: self.find_element(By.NAME, "q")

    def test_search(self):
        self.driver = webdriver.Firefox()
        self.driver.get("https://google.com")
        self.search_input().send_keys("selenium python")
        self.search_input_1().clear()
\$\endgroup\$
1
\$\begingroup\$

If I were to use "find by" PageFactory-like notation in Python, I would go with the one proposed here - similar to your versions, but more concise and supports more features:

from pageobject_support import callable_find_by as find_by

class GoogleSearchPage(object):
    search_input = find_by(how=By.NAME, using='q')

Old Answer (in case there is anything useful there)

I would go further and follow the Page Object pattern, creating abstractions for the pages and elements you are working with, as demonstrated in the selenium documentation. This way you are isolating your locators from the logic of the test providing an "API" to work with a particular page.

Here is one way to do it - pay attention to how simple and concise the actual test has become:

import unittest

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys


class MainPageLocators(object):
    """A class for main page locators. All main page locators should come here"""
    SEARCH_INPUT = (By.NAME, 'q')


class BasePage(object):
    """Base class to initialize the base page that will be called from all pages"""

    def __init__(self, driver):
        self.driver = driver


class MainPage(BasePage):
    """Home page action methods come here."""

    def search(self, search_query):
        """Triggers the search"""
        search_input = self.driver.find_element(*MainPageLocators.SEARCH_INPUT)
        search_input.send_keys(search_query)
        search_input.send_keys(Keys.ENTER)


class TestGoogle(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Firefox()
        self.driver.get("https://google.com")

    def tearDown(self):
        self.driver.close()

    def test_search(self):
        main_page = MainPage(self.driver)
        main_page.search("selenium python")

Note that you may also want a separate class for an element, but this should be good enough to get you started.

Also note that I'm using a unittest.TestCase as a base class for your test which, aside from bringing other benefits, allows to nicely start and close a browser via setUp and tearDown.

\$\endgroup\$
  • \$\begingroup\$ I am also using the page object patter. however this is just for the self.driver.find_element(*MainPageLocators.SEARCH_INPUT) syntax, similar to how we do in PageFactory in Java \$\endgroup\$ – Gaurang Shah Aug 24 '17 at 13:21
  • \$\begingroup\$ @GaurangShah gotcha, updated the answer a bit. Check it out, thanks. \$\endgroup\$ – alecxe Aug 24 '17 at 13:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.