Test Automation With Python
Tags: python, testing, programming, tutorial
Published: 2022-07-28 05:53:47

---
canonical_url: https://blog.loadero.com/2022/01/20/test-automation-with-python/
---
According to [IEEE Spectrum](https://spectrum.ieee.org/top-programming-languages/) Python is the top programming language of 2021, and since April Loadero supports Python as a test script language. Many engineers agree that test automation with Python is an excellent choice, and in this blog post, we’ll show the basics of it.

Python tests in Loadero use the [Py-TestUI](https://github.com/testdevlab/Py-TestUI) framework. Py-TestUI wraps and implements additional features for Selenium Python binding. This means that Loadero Python tests can utilize the full power of Selenium and other cool features provided by Py-TestUI.

## Test Structure

Every Python test starts with

``` 
def test_on_loadero(driver: TestUIDriver) -> None:
```

This function is like the `main` function in other programming languages. It will be called once the test execution is started. All of the test logic must originate from this function. This means that additional functions outside of the `test_on_loadero` function can be added, but they must be called from the `test_on_loadero` function to have any effect.
## Driver

Loadero tests automate browser interactions as if they were done by a human to allow for repeated execution, parallel tests, and scale-up for load testing. Tests can do almost any action that a human can in a browser, for example:

- Navigate to URL
- Click on links and elements
- Input text
- Copy text

These actions are achieved in a test with the `driver` object. `driver` wraps the workhorse of the browser test – [Selenium WebDriver](https://www.selenium.dev/selenium/docs/api/py/index.html#drivers) and is of type [TestUIDriver](https://github.com/testdevlab/Py-TestUI/blob/master/testui/support/testui_driver.py#L18). `TestUIDriver` implements commonly used browser interactions to improve ease of use but at the same time allows to access the underlying Selenium WebDriver for more complex browser interactions.

`driver` object is initialized and configured at the start of every test and passed as an argument to the `test_on_loadero` function.

Let’s look at common browser interactions and how to implement them in a test script. 
## Navigation

To start interacting with a web page, it first has to be opened. To do that call the following method

```
TestUIDriver.navigate_to(url: str) -> None
```
Argument `url` is the URL of a web page to open.
Here is a simple test that demonstrates the usage of `navigate_to`.

```
def test_on_loadero(driver: TestUIDriver) -> None:
    driver.navigate_to("https://duckduckgo.com/")
    driver.save_screenshot("duckduckgo.png")
```
Additionally, the test calls

```
TestUIDriver.save_screenshot(image_name: str) -> str
```
This method will, as the name implies, capture the state of the browser at the moment of the `save_screenshot` method call and save it with the name supplied by `image_name` argument. After the test finishes execution, all screenshots taken during the test will be available in the artifacts tab in the [Loadero result page of a single test participant.](https://blog.loadero.com/2020/03/27/loadero-report-explained/)

> **Tip**: Taking screenshots during a test is a common practice that helps test debugging or manually reviewing what was on the test participant’s screen at the important stages of your test.

## Clicks
A very fundamental browser interaction is the click. To interact with an element it first has to be located with the `e` method.

```
TestUIDriver.e(locator_type: str, locator: str) -> Elements:
```
`locator_type` argument describes the location method of an element and can have values:
- `css` – locate element by CSS selector
- `name` – locate element by name
- `className` – locate the element by its class name
- `xpath` – locate element by XPath

`locator` – describes how to locate the element with the location method set by `locator_type` argument. To learn more about using CSS selectors and XPath locators in your Selenium test automation scripts make sure to read [this blog post](https://blog.loadero.com/2021/12/29/css-selectors-and-xpath-locators-in-selenium-test-automation-scripts/).

An attentive reader might have noticed that `e` method has return type `Elements` – plural, but I have been using elements in a singular form so far. This is because `Elements` object has more advanced features (for example – [locating multiple elements at once](https://github.com/testdevlab/Py-TestUI/blob/master/testui/elements/testui_collection.py#L26), [image matching](https://github.com/testdevlab/Py-TestUI/blob/master/testui/elements/testui_element.py#L494)) that this blog post does not cover. So in an attempt not to confuse the reader these topics will be skipped.

After locating the desired element it can be clicked on with the `click` method.

```
Elements.click() -> Elements:
```
There is nothing in the way for calling `click` right after an element has been located, but a good practice is to check if the element is visible with a runtime assertion before clicking on it. If the element is visible then it has had enough time to load and can be interacted with. Doing this allows avoiding test failures caused by attempting to click on an element that has not loaded yet. We use a lot in tests we create for our customers and advise you to do the same.

`wait_until_visible` method does as the name suggests – waits for the element to load and become visible before attempting further interactions.

```
Elements.wait_until_visible(seconds=10.0, log=True) -> Elements:
```
Argument `seconds` with a default value of 10.0 specifies the amount of time the test will wait until the element becomes visible. If the element is not visible after waiting the specified time an error will be raised and the test will fail.

Argument `log` with a default value True specifies whether to log the result of the `wait_until_visible` method call. This argument generally should not be changed and can be ignored. Many `Elements` methods have a `log` argument and it can be ignored in all of them.

Here is a simple test script showcasing everything shown so far. You can put everything learned so far to test with [Loadero’s free trial](https://app.loadero.com/signup). You can also find the script example in [Loadero’s Github repository.](https://github.com/loadero/examples/blob/master/python/src/part1/duckduckgo_click.py)

```
def test_on_loadero(driver: TestUIDriver) -> None:
    # Opens the search engine DuckDuckGo with default search query of
    # google.com
    driver.navigate_to("https://duckduckgo.com/?q=google.com")
    # Locates an element with a CSS selector that is pointing to the first
    # search results title, waits for the element to become visible and clicks
    # on it.
    driver.e("css", "#r1-0 > div > h2").wait_until_visible().click()
    # Ensures that the web page has loaded before taking a screenshot.
    driver.e("css", "body > div:first-of-type").wait_until_visible()
    driver.save_screenshot("google.png")
```

## Input Text
The previous test script example was cheating a bit. Realistically a human user would insert the search query “google.com” themselves and wouldn’t be using a specially prepared URL. To simulate this behavior, tests can input text with the `.send_keys` method.
```
Elements.send_keys(value: str, log=True) -> Elements:
```
`value` argument specifies the text that will be sent to an element.
To clear the input value that was set by `send_keys` or an element has by default use `clear` method.
```
Elements.clear() -> None:
```

## Retrieving Content of an element
Browser interactions can be generalized as a feedback loop where the next interaction is determined by the resulting content of a web page. Tests need a way to retrieve the content of a web page or more specifically the content of a single element to implement logic that decides what the next interaction should be. This section will cover the other half of the browser interaction feedback loop – content retrieval.

Most HTML elements have content, with few exceptions like `<br>` element, that is rendered to the web page and can be interacted with.

To retrieve the textual value of an element use
```
Elements.get_text() -> str:
```

## Putting Everything Learned To Use
It’s time to combine all the commands we have described in a single test automation script. [This script example](https://github.com/loadero/examples/blob/master/python/src/part1/top_search_results.py) performs a search for a specific query on the DuckDuckGo search engine and prints out the top results.
```
def test_on_loadero(driver: TestUIDriver) -> None:
    # The main logic of the test is in top_search_results function
    print(top_search_results(driver, "loadero", 10))
# top_search_results returns the top n search results for search_query.
def top_search_results(driver: TestUIDriver, search_query: str, n: int) -> str:
    # Limits the search result count to 10, because a single search query in
    # DuckDuckGo search engine returns only 10 results.
    n = min(n, 10)
    # Selectors.
    home_page_search_bar = "#search_form_input_homepage"
    home_page_search_button = "#search_button_homepage"
    # Opens the search engine DuckDuckGo.
    driver.navigate_to("https://duckduckgo.com/")
    # Locates search bar, waits for the element to load and sends a search query
    # to it
    driver.e("css", home_page_search_bar).wait_until_visible().send_keys(
        search_query
    )
    # Locates search button, verifies that it is visible and clicks it.
    driver.e("css", home_page_search_button).wait_until_visible().click()
    result = f"Top {n} DuckDuckGo search results for {search_query} ->\n"
    # Iterates over top n search results
    for i in range(n):
        # Creates a CSS selector that indicates to the search result title.
        selector = f"#r1-{i} > div > h2 > a.result__a"
        # Locates the search element and verifies that it is visible.
        search_result_element = driver.e("css", selector).wait_until_visible()
        # Retrives the title of search result and adds it to result string.
        title = search_result_element.get_text()
        result += f"\t {title} \n"
    return result
```
You can find the output of this test script in Loadero’s [single participants result pages ](https://wiki.loadero.com/results/participant-view/)logs tab under Selenium log. The output would log something like this:
```
Top 10 DuckDuckGo search results for loadero ->
     Loadero - Performance and Load Testing Tool
     Loadero | LinkedIn
     Loadero Pricing, Alternatives & More 2022 - Capterra
     Loadero - Home | Facebook
     GitHub - loadero/examples: Test script examples that are ...
     Loadero - YouTube
     Loadero - your performance & load testing partner from the ...
     Application Load Testing Tools for API Endpoints with ...
     Tractors - Tractor Loader Backhoe - B26 | Kubota
     EZ Loader TMS | EZ Loader TMS
```

We covered the basics of working on test automation with Python. You can create a test similar to what we described and run it multiple times free of charge with [Loadero’s free trial](https://app.loadero.com/signup). To continue learning to use Python for your tests in Loadero make sure to visit our [Wik](https://wiki.loadero.com/testui-python/)i, where you can find information about [custom commands](https://wiki.loadero.com/testui-python/custom-commands/) that extend the functionality WebDriver and PyTestUI, [variables](https://wiki.loadero.com/testui-python/variables/) that hold the relevant information about the test participant, and more [script examples](https://wiki.loadero.com/testui-python/script-examples/) of test automation with Python. We will be glad to see you back again.