Tutorial for test usage

Canonical implementation

This is the simplest implementation to warm up the framework. It uses the OpenApp and CloseApp transactions to open the web page of Google, to assert the title of the page is Google and to close the web application. More details about each component of the framework are explained in further sessions. First install Selenium with pip install selenium

# test_guara.py

from guara import it
from guara.transaction import Application, AbstractTransaction
from selenium import webdriver


class OpenApp(AbstractTransaction):
    def do(
        self, url: str,
    ) -> str:
        self._driver.get(url)
        return self._driver.title


class CloseApp(AbstractTransaction):
    def do(self) -> None:
        self._driver.quit()


def test_canonical():
    google = Application(webdriver.Chrome())
    google.when(OpenApp, url="http://www.google.com",).asserts(it.IsEqualTo,"Google")
    google.execute(CloseApp)

Basic practical example

This is a basic search of the term “guara” on Google. To follow the steps create the files home.py and test_tutorial.py at the same folder.

# home.py

from guara.transaction import AbstractTransaction
from selenium.webdriver.common.by import By


class Search(AbstractTransaction):
    def __init__(self, driver):
        super().__init__(driver)

    def do(self, text):
        # Sends the received text to the textbox in the UI
        self._driver.find_element(By.NAME, "q").send_keys(text)
        
        # Click the button to search
        self._driver.find_element(By.NAME, "btnK").click()
        
        # Waits the next page appears and returns the label of the first tab "All".
        # It will be used by assertions in the next sessions.  
        return self._driver.find_element(
            By.CSS_SELECTOR, ".Ap1Qsc > a:nth-child(1) > div:nth-child(1)"
        ).text
  • class Search: is a concrete transaction. Notice that the name of the class is an action and not a noun as usually saw in OOP. It is intentional to make the statement in the test more natural.

  • def __init__: is the same for all transactions. It passes the driver to the AbstractTransaction.

  • def do: is the ugly implementation of the method. It uses the private attribute self._driver inherited from AbstractTransaction to call find_element, send_keys, click and text from Selenium Webdriver. Notice the parameter text. It is received from the automation via kwargs. More details in further sessions.

# test_tutorial.py

import pytest

# Imports the module with the transactions of the Home page
import home

from selenium import webdriver

# Imports the Application to build and run the automation
from guara.application import Application

# Imports the module with the strategies to asset the result
from guara import it

@pytest.fixture
def google():
    # Instantiates the Application to run the automation
    google = Application(webdriver.Chrome())

    # Some interesting things happen here.
    # The framework is used to setup the web application.
    # The method `at` from `app` is the key point here as it
    # receives a transaction (AbstractTransaction) and its `kwargs`.
    # Internally `at` executes the `do` method of the transaction and
    # holds the result in the property `result` which is going to be
    # presented soon.
    # `OpenApp` is a concrete transaction.
    # The `url` is passed to the `at` method by `kwargs`.
    # The result returned by `at` is asserted by `asserts`
    # using the strategy `it.IsEqualTo`.
    google.given(
        OpenApp,
        url="http://www.google.com",
    ).then(it.IsEqualTo, "Google")
    yield google

    # Uses the concrete transaction `CloseApp` to close the web application
    google.execute(CloseApp)


def test_google_search(google: Application):
    # With the `app` received from the fixture the similar things
    # explained previously in the fixture happens.
    # The transaction `home.Search` with the parameter `text`
    # is passed to `at` and the result is asserted by `asserts` with
    # the strategy `it.IsEqualTo`
    google.at(home.Search, text="guara").asserts(it.IsEqualTo, "All")

  • class Application: is the runner of the automation. It receives the driver and passes it hand by hand to transactions.

  • def at: receives the transaction created on home.py and its parameters. Notice the usage of the module name home to make the readability of the statement as plain English. The parameters are passed explicitly for the same purpose. So the google.at(home.Search, text="guara") is read Google at home [page] search [for] text "guara". The terms page and for could be added to the implementation to make it more explicit, like google.at(homePage.Search, for_text="guara"). This is a decision the tester may make while developing the transactions.

  • def asserts: receives a strategy to compare the result against an expected value. Again, the focus on readability is kept. So, asserts(it.IsEqualTo, "All") can be read asserts it is equal to 'All'

  • it.IsEqualTo: is one of the strategies to compare the actual and the expected result. Other example is the it.Contains which checks if the value is present in the page. Notice that the assertion is very simple: it validates just one value. The intention here is keep the framework simple, but robust. The tester is able to extend the strategies inheriting from IAssertion.