Friday, September 1, 2017

Selenium Python Object Repository - Using Lambda

in the last post I discussed how to create object repository using decorator. if you haven't read the post, please read it here

I am going to take the same example to demonstrate how to use lambda (anonymous function).

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


class TestGoogle(object):
    
    search_input = 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")
Pros of Using
  • all the elements are in one place in the file (class), so if any element change it's easy and fast
  • it's a function, so every time a object would be created, you should never get StaleElementRefereceException
Cons of Using
  • You will have to keep in mind it's a function not a variable
  • Every time a new object would be created, so it could be a overhead.

Thursday, August 24, 2017

Selenium Python Object Repository - Using decorator

In the series of posts I will try to explain how to create the object repository when you are writing selenium tests using python. There are different ways, few more simple than others but finally it's upto you which to use and how to use it.

Java has PageFactory which allows a nicer, cleaner way to create WebElement object repository.  It doesn't actually creates the object it's just do the lazy initialization. which means the first time you do some action on this object and it's actually created.

I wanted to something like this Python, I searched it but didn't find any satisfactory answer. and So I write my own code.  It look similar to how you initialize the object in Java, however, it's different in few aspects. For one it doesn't actually do the lazy initialization, however it creates the new object every time you do some action on it.  However, it has advantages as well.

Remember,  StaleElemementReferenceException, it's very less likely you will get this as it creates new object every time.

For this I am using Decorator, if don't know what is decorator, it's simply a function which takes a function as a input and returns you a brand new function. However, I would advice you to read more about this.

Now let's just to code.


Without Object Repository


class TestGoogle(object):

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

And now, with Object Repository
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")

If you have noticed, search_input is a function and not a variable. The reason for this is, Python don't have a decorator for variable, at least yet.  And so you need to call the function which will give you a WebElement object on which you can do multiple actions. 

Tuesday, February 21, 2017

PyTest with Selenium - HTML report with Screenshot

recently I was working with Py.Test with selenium. It's really powerful tool with awesome fixtures. It generates JUnit XML report as well which is good to be consumed by Jenkins. However, I needed an HTML report as well with embedded screenshot for the ease of identifying the issue. And this is how I did it finally after doing some googling.

Generate HTML Report of PyTest 

Pytest-html plugin is available which you can use to generate the beautiful Report. The all you have to do is install the plugin and run your test case with this plugin. 

Embede ScreenShot When Test Case Fails

PyTest-html plugin allows you to extend the plugin and that's the best thing about this plugin. 
conftest.py

from selenium import webdriver
import pytest
driver = None


@pytest.mark.hookwrapper
def pytest_runtest_makereport(item):
    """
    Extends the PyTest Plugin to take and embed screenshot in html report, whenever test fails.
    :param item:
    """
    pytest_html = item.config.pluginmanager.getplugin('html')
    outcome = yield
    report = outcome.get_result()
    extra = getattr(report, 'extra', [])

    if report.when == 'call' or report.when == "setup":
        xfail = hasattr(report, 'wasxfail')
        if (report.skipped and xfail) or (report.failed and not xfail):
            file_name = report.nodeid.replace("::", "_")+".png"
            _capture_screenshot(file_name)
            if file_name:
                html = '<div><img src="%s" alt="screenshot" style="width:304px;height:228px;" ' \
                       'onclick="window.open(this.src)" align="right"/></div>' % file_name
                extra.append(pytest_html.extras.html(html))
        report.extra = extra


def _capture_screenshot(name):
    driver.get_screenshot_as_file(name)


@pytest.fixture(scope='session', autouse=True)
def browser():
    global driver
    if driver is None:
        driver = webdriver.Firefox()
    return driver
test_screenshot.py
def test_screenshot_on_test_failure(browser):
    # driver = webdriver.Firefox()
    browser.get("https://google.com")
    assert False