The pattern Explained
AbstractTransaction: This is the class from which all transactions inherit. Thedomethod is implemented by each transaction. In this method, calls to WebDriver are placed. If the method returns something, like a string, the automation can use it for assertions.OpenAppandCloseAppare examples of concrete transactions.
IAssertion: This is the interface implemented by all concrete assertions.The
assertsmethod of each concrete assertion contains the logic to perform validations. For example, theIsEqualToconcrete assertion compares theresultwith the expected value provided by the tester.Testers can inherit from this interface to add new sub-classes of validations that the framework does not natively support. More details here.
Application: This is the runner of the automation. It executes thedomethod of each transaction and validates the result using theassertsmethod.The
assertsmethod receives a reference to anIAssertioninstance. It implements theStrategy Pattern (GoF)to allow its behavior to change at runtime.Another important component of the
Applicationis theresultproperty. It holds the result of the transaction, which can be used byassertsor inspected by the test using the native built-inassertmethod.
Using it
The idea is to group blocks of interactions into classes. These classes inherit from AbstractTransaction and override the do method.
Each transaction is passed to the Application instance, which provides the methods at and asserts. These are the only two methods necessary to orchestrate the automation. While it is primarily bound to Selenium WebDriver, experience shows that it can also be used to test REST APIs, unit tests and can be executed in asynchronous mode (check the examples folder).
When the framework is in action, it follows a highly repetitive pattern. Notice the use of the at method to invoke transactions and the asserts method to apply assertion strategies. Also, the automation is described in plain English improving the comprehension of the code.
from selenium import webdriver
from pages import home, contact, info, setup
from guara.application import Application
from guara import it
def test_sample_web_page():
app = Application(webdriver.Chrome())
app.at(setup.OpenApp, url="https://anyhost.com/",)
app.at(home.ChangeToPortuguese).asserts(it.IsEqualTo, content_in_portuguese)
app.at(home.ChangeToEnglish).asserts(IsEqualto, content_in_english)
app.at(info.NavigateTo).asserts(
it.Contains, "This project was born"
)
app.at(setup.CloseApp)
itis the module which contains the concrete assertions.
The ugly code which calls the webdriver is like this:
class ChangeToPortuguese(AbstractTransaction):
def __init__(self, driver):
super().__init__(driver)
# Implements the `do` method and returns the `result`
def do(self, **kwargs):
self._driver.find_element(
By.CSS_SELECTOR, ".btn:nth-child(3) > button:nth-child(1) > img"
).click()
self._driver.find_element(By.CSS_SELECTOR, ".col-md-10").click()
return self._driver.find_element(By.CSS_SELECTOR, "label:nth-child(1)").text
Again, it is a very repetitive activity:
Create a class representing the transaction, in this case, the transaction changes the language to Portuguese
Inherits from
AbstractTransactionImplements the
domethodOptional: Returns the result of the transaction