Tests runners integration
Behave (BDD)
Behave tests should be developed as usual, only environment.py file should be modified to initialize driver and the rest of Toolium configuration.
Environment methods should call to the corresponding Toolium environment methods, as can be seen in the following example:
from toolium.behave.environment import (before_all as toolium_before_all, before_feature as toolium_before_feature,
before_scenario as toolium_before_scenario,
after_scenario as toolium_after_scenario,
after_feature as toolium_after_feature, after_all as toolium_after_all)
def before_all(context):
toolium_before_all(context)
def before_feature(context, feature):
toolium_before_feature(context, feature)
def before_scenario(context, scenario):
toolium_before_scenario(context, scenario)
def after_scenario(context, scenario):
toolium_after_scenario(context, scenario)
def after_feature(context, feature):
toolium_after_feature(context, feature)
def after_all(context):
toolium_after_all(context)
After initialization, the following attributes will be available in behave context:
context.toolium_config: dictionary with Toolium configuration, readed from properties.cfgcontext.driver_wrapper: DriverWrapper instancecontext.driver: Selenium, Playwright or Appium driver instancecontext.utils: Utils instance
Behave userdata properties
Toolium properties can be modified from behave userdata configuration. For example, to select the driver type from command line instead of using the driver type defined in properties.cfg:
$ behave -D Driver_type=chrome
Behave - Dynamic Environment
Optionally, some actions (labels) are defined in the Feature description as:
Actions Before the Feature:
Actions Before each scenario:
Actions After each scenario:
Actions After the Feature:
With a steps list executed in each moment identified with the label as the environment.py file. These steps are defined similar to others one.
Each step block is separated by a blank line.
Behave keywords are supported (Given, When, Then, And, But, Check, Setup).
Note
When using Drivers, Actions Before the Feature and Actions After the Feature directives (in the “dynamic environment” of a Feature) are only available if the execution for that Feature has been configured to reuse the driver. Otherwise, unexpected exceptions can be raised and execution may not finish successfully.
Example:
@reuse_driver
Feature: Tests with the dynamic environment
As a behave operator using multiples scenarios
I want to append actions before the feature, before each scenario, after each scenario and after the feature.
Actions Before the Feature:
Given wait 3 seconds
And waitrty 3 seconds
And wait 3 seconds
And step with a table
| parameter | value |
| sub_fields_1 | sub_value 1 |
| sub_fields_2 | sub_value 2 |
Actions Before each Scenario:
Given the user navigates to the "www.google.es" url
When the user logs in with username and password
And wait 1 seconds
And wait 1 seconds
Actions After each Scenario:
Then wait 2 seconds
And wait 2 seconds
Actions After the Feature:
Then wait 4 seconds
And step with another step executed dynamically
And wait 4 seconds
All kind of steps are allowed:
with tables
executing another step internally
In case that a step of dynamic environment fails, an exception is printed on console, i.e. ‘waitrty 3 seconds’ step. When this happens, steps of the affected scenarios for that precondition are not executed (skipped) and, after that, first step defined in those scenarios will be automatically failed because of that precondition exception, in order to properly fail the execution and show the stats.
Behave variables transformation
Toolium provides a set of functions that allow the transformation of specific string tags into different values. See below their values, along with their associated replacement logic (click here or check the dataset module for more implementation details):
[STRING_WITH_LENGTH_XX]: Generates a fixed length string[INTEGER_WITH_LENGTH_XX]: Generates a fixed length integer[STRING_ARRAY_WITH_LENGTH_XX]: Generates a fixed length array of strings[INTEGER_ARRAY_WITH_LENGTH_XX]: Generates a fixed length array of integers[JSON_WITH_LENGTH_XX]: Generates a fixed length JSON[MISSING_PARAM]: Generates a None object[NULL]: Generates a None object[TRUE]: Generates a boolean True[FALSE]: Generates a boolean False[EMPTY]: Generates an empty string[B]: Generates a blank space[UUID]: Generates a v4 UUID[RANDOM]: Generates a random value[RANDOM_PHONE_NUMBER]: Generates a random phone number for language and country configured in dataset.language and dataset.country[TIMESTAMP]: Generates a timestamp from the current time[DATETIME]: Generates a datetime from the current time (UTC)[NOW]: Similar to DATETIME without microseconds; the format depends on the language[NOW(%Y-%m-%dT%H:%M:%SZ)]: Same as NOW but using an specific format by the python strftime function of the datetime module. When using the %f placeholder, the number of digits to be used can be set like this: %3f[NOW + 2 DAYS]: Similar to NOW but two days later[NOW - 1 MINUTES]: Similar to NOW but one minute earlier[NOW(%Y-%m-%dT%H:%M:%SZ) - 7 DAYS]: Similar to NOW but seven days before and with the indicated format[TODAY]: Similar to NOW without time; the format depends on the language[TODAY + 2 DAYS]: Similar to NOW, but two days later[STR:xxxx]: Cast xxxx to a string[INT:xxxx]: Cast xxxx to an int[FLOAT:xxxx]: Cast xxxx to a float[LIST:xxxx]: Cast xxxx to a list[DICT:xxxx]: Cast xxxx to a dict[UPPER:xxxx]: Converts xxxx to upper case[LOWER:xxxx]: Converts xxxx to lower case[REPLACE:xxxx::SUBSTRING_TO_BE_REPLACED::SUBSTRING_TO_USE_AS_REPLACEMENT]: Replaces a substring with another in xxxx string[TITLE:xxxx]: Applies python’s string title() method to xxxx string[ROUND:xxxx::N]: Rounds given number xxxx to N digits in its fractional part[SHARP]: Generates a sharp string ‘#’
There are also some special tags that allow to use parameter values configured at different sources defined by the map_param method:
[CONF:xxxx]: Value from the config dict in dataset.project_config for the key xxxx[LANG:xxxx]: String from the texts dict in dataset.language_terms for the key xxxx, using the language specified in dataset.language[LANG:xxxx::OTHER_LANGUAGE]: String from the texts dict in dataset.language terms for the key xxxx, using the language specified in OTHER_LANGUAGE[POE:xxxx]: Definition(s) from the POEditor terms list in dataset.poeditor_terms for the term xxxx (see poeditor module for details)[TOOLIUM:xxxx]: Value from the toolium config in dataset.toolium_config for the key xxxx[CONTEXT:xxxx]: Value from the behave context storage dict in dataset.behave_context for the key xxxx, or value of the behave context attribute xxxx, if the former does not exist[ENV:xxxx]: Value of the OS environment variable xxxx[FILE:xxxx]: String with the content of the file in the path xxxx[BASE64:xxxx]: String with the base64 representation of the file content in the path xxxx
In order to apply the string replacements in your code, import and call the corresponding function. E.g.:
from toolium.utils.dataset import map_param, replace_param
mapped_param = map_param('[TOOLIUM:Driver_chrome_driver_path]')
replaced_param = replace_param('[NOW - 1 MINUTES]')
Please note that, by default, the replace_param function tries to convert the resulting value to a native Python datatype. If that does not work for you, do not forget to set the infer_param_type parameter to False.
Nose2 / unittest
To use Toolium with nose2 or unittest, you only need to extend from one of the base test case classes provided by Toolium:
BasicTestCase for API tests
SeleniumTestCase for Selenium tests
AppiumTestCase for Appium tests
These classes already implement the setup and teardown logic to initialize and close the driver automatically.
Example:
from toolium.test_cases import SeleniumTestCase
from web_nose2.pageobjects.login import LoginPageObject
class LoginTest(SeleniumTestCase):
def test_successful_login(self):
user = {'username': 'tomsmith', 'password': 'SuperSecretPassword!'}
secure_area = LoginPageObject().open().login(user)
self.assertIn('You logged into a secure area!', secure_area.message.get_message())
You can see a complete example of nose2 integration with Toolium in toolium-examples repository.
Pytest
To run tests with pytest using Toolium, simply import Toolium’s fixtures in your conftest.py file:
from toolium.pytest_fixtures import *
This will automatically initialize the driver before each test, module, or session, and close it automatically after the test execution, according to your configuration.
Example:
from web_nose2.pageobjects.login import LoginPageObject
def test_successful_login():
user = {'username': 'tomsmith', 'password': 'SuperSecretPassword!'}
secure_area = LoginPageObject().open().login(user)
assert 'You logged into a secure area!' in secure_area.message.get_message()
You can see a complete example of pytest integration with Toolium in toolium-examples repository.
Pytest also allows to run tests that extend from a unittest.TestCase class. In this case, it is recommended to
extend directly from unittest.TestCase, not from Toolium’s test case classes. In this scenario, the driver will be
initialized using the Toolium fixtures (as shown above), not with setUp and tearDown methods. This ensures proper driver
management and compatibility with pytest’s fixture system.
Example:
import unittest
from web_nose2.pageobjects.login import LoginPageObject
class LoginTest(unittest.TestCase):
def test_successful_login(self):
user = {'username': 'tomsmith', 'password': 'SuperSecretPassword!'}
secure_area = LoginPageObject().open().login(user)
self.assertIn('You logged into a secure area!', secure_area.message.get_message())