PYON-BEHAVE | Appium-based UI Automated Testing Framework in Python-Behave for Native Apps
Pyon UI Test Automation project is available to implement UI tests for web and mobile applications with the following stacks and approaches:
- Programming Language: Python-based.
- Framework for behavioural tests: Behave
- Minimal library requirements: Appium Python Client and optionally: Selenium
To know how you can configure your environment to implement and execute this project locally or even remotely, follow all the instructions from this documentation. So, let's get started and good luck!
Go to GITHUB and CLONE the project using GIT (download and install GIT from here)
In you local machine, choose you local repository and clone the project using SSH for Mac OS or Linux platforms with this command:
git clone git@github.com:hudsonssrosa/pyon-behave-ui-tests-nativeapps.git
If you are having issues when cloning or pushing to the repository make sure you have all your SSH keys in place. Click here for more information about it.
Download and install the latest Python version (3.8 or over). Then, in any terminal, try this command to check if Python is correctly installed:
python
Once you have opened the project in an IDE of your preference (suggestion: install Visual Studio Code or PyCharm CE), then you will need to set the Python interpreter for the project.
After this, you are able to create the Python Virtual Environment for the PyonUIT project and install all the requirements needed (libraries/packages). You just need to run for the first time the setup_python_env_update.py
and then the virtual environment as well the libraries in requirements.txt
will be automatically installed for you.
- In Windows:
python update.py
- In MacOSX or Linux:
python3 update.py
Increment this command with CLI presented in next section 4.3, if you want to simulate the PyonUIT using Docker.
By default, the tests will run locally on APPIUM, but you have 3 ways to perform your execution.
To check if the environment is totally operational to begin with some implementation, or even check the existing tests, you might dealing with the environment variables to prepare for an execution. Thus, copy the file env_settings.properties.local
and paste the new one in project's root (in the same place as the original file) renaming it to env_settings.properties
. So, you can edit the properties freely, because this file is ignored by GIT versioning.
Into this file, to consider a development setting, ensure the property development_mode
is set as true
. With this, all the properties that start with debug_...
will be considered in a project debugging overwriting any command lines from CLI:
development_mode = true
debug_flag_environment = staging
debug_flag_target = local_emulation
debug_flag_os = Android
debug_flag_os_version = 11.0
debug_flag_device_name = Samsung Galaxy A51
debug_flag_mode = native_app
debug_behave_tags = login-sample
debug_behave_excluded_tags = wip
debug_flag_orientation = Portrait
debug_flag_language = en
debug_flag_locale = en_GB
- To generate Allure Reports locally, make sure you have
Java
installed and the flaggenerate_report = true
on yourenv_settings.properties
.
After any implementation into the PyonUIT, it is recommended to validate the tests simulating an execution capable to inject parameters in environment variables, like it is performed in a build from a CI server. To validate a test execution, keep in mind to run in a remote server such as BrowserStack or any other supported by PyonUIT in fixtures.py
. Before this, you also will need to copy the file run_behave.sh.local
and paste the new one in project's root (in the same place as the original file) renaming it to run_behave.sh
to be ignored in commits.
Into this script file, you can set those environment variables, like this:
PYON_ENVIRONMENT='staging'
PYON_TARGET='local_emulation'
PYON_MODE='native_app'
PYON_OS='Android'
PYON_OS_VERSION='11.0'
PYON_DEVICE='Samsung Galaxy A51'
PYON_ORIENTATION='Portrait'
PYON_LANGUAGE='en'
PYON_LOCALE='en_GB'
PYON_APP_PATH='.resources/app_distribution/Sample.apk'
PYON_TAGS=
PYON_EXCLUDED_TAG='wip'
You can handle all those parameters presented previously (in section 4.2) setting them directly via CLI. You just need to pass the desired values in the arguments by command line. First of all, call the main runner file in the terminal and press Enter. So, try this:
python3 behave_runner.py --help
You might see all the supported arguments that you can use:
usage: behave_runner.py [options]
optional arguments:
-h, --help show this help message and exit
--environment {staging,dev,production}
==> Environment to execute the tests (default = staging). Find the app URLs in properties file
--target {remote_emulation,local_emulation,bs,real_device}
==> Platform to execute the mobile tests (default = local_emulation): BS - BrowserStack
--mode {native_app} ==> Execution mode according the mobile platform (default = native_app)
--os {iOS,Android,} ==> Mobile Operational System
--os_version {14.5,14.4,14.3,14.2,14.1,14.0,13.0,12.0,11.0,10.0,9.0,8.1,8.0,7.1,7.0,6.0,5.0,4.4,}
==> Mobile platform versions
--device_name {local,Google Pixel 4 XL,Google Pixel 4,Google Pixel 3a XL,Google Pixel 3a,Google Pixel 3 XL,Google Pixel 3,Google Pixel 2,Google Pixel,Google Nexus 6,Google Nexus 5,iPhone 12 Pro Max,iPhone 12 Pro,iPhone 12,iPhone 11 Pro Max,iPhone 11 Pro,iPhone 11,iPhone XS Max,iPhone XS,iPhone XR,iPhone X,iPhone 8 Plus,iPhone 8,iPhone 7 Plus,iPhone 7,iPhone 6S Plus,iPhone 6S,iPhone 6,iPhone SE 2020,iPhone SE,iPad,iPad Pro 12.9 2020,iPad Pro 12.9 2018,iPad Pro 11 2020,iPad Mini 2019,iPad Air 2019,iPad 7th,iPad Pro 11 2018,iPad Pro 9.7 2016,iPad Pro 12.9 2017,iPad Mini 4,iPad 6th,iPad 5th,Motorola Moto G7 Play,Motorola Moto X 2nd Gen,Motorola Moto X 2nd Gen,OnePlus 8,OnePlus 7,OnePlus 7T,OnePlus 6T,Samsung Galaxy S20,Samsung Galaxy S20 Plus,Samsung Galaxy S20 Ultra,Samsung Galaxy Note 20 Ultra,Samsung Galaxy Note 20,Samsung Galaxy Note 10 Plus,Samsung Galaxy Note 10,Samsung Galaxy Note 9,Samsung Galaxy Note 8,Samsung Galaxy Note 4,Samsung Galaxy A51,Samsung Galaxy A11,Samsung Galaxy A10,Samsung Galaxy S10e,Samsung Galaxy S10 Plus,Samsung Galaxy S10,Samsung Galaxy S9 Plus,Samsung Galaxy S9,Samsung Galaxy S8 Plus,Samsung Galaxy S8,Samsung Galaxy S7,Samsung Galaxy S6,Samsung Galaxy J7 Prime,Samsung Galaxy Tab S6,Samsung Galaxy Tab S5e,Samsung Galaxy Tab S4,Samsung Galaxy Tab S3,Samsung Galaxy Tab 4,Vivo Y50,Xiaomi Redmi Note 8,Xiaomi Redmi Note 7}
==> The device name models (check the platform version supported in --os_version)
--app_path APP_PATH ==> Relative or absolute path of an .APK or .IPA file (format is automatically recognized if --os arg is set)
--orientation {Landscape,Portrait}
==> Screen orientation for mobile executions (default = Portrait)
--language {,af,ar,be,bg,ca,cs,cy,da,de,el,en,eo,es,et,fr,ga,gl,gsw,hi,it,ja,nb,nl,pl,pt,ro,rof,ru,sv,tr,uk,zh,zu}
==> Language to set for iOS (XCUITest driver only) and Android (default = )
--locale {,af_,af_ZA,ar_,ar_001,ar_AE,ar_QA,ar_SA,be_,be_BY,bg_,bg_BG,ca_,ca_AD,ca_ES,ca_FR,ca_IT,cs_,cs_CZ,cy_,cy_GB,da_,da_DK,da_GL,de_,de_AT,de_BE,de_CH,de_DE,de_LI,de_LU,el_,el_CY,el_GR,en_,en_001,en_150,en_AU,en_BE,en_GB,en_HK,en_IE,en_IN,en_NZ,en_SG,en_US,en_ZA,eo_,es_,es_419,es_ES,et_,et_EE,fr_,fr_BE,fr_LU,ga_,ga_IE,gl_,gl_ES,gsw_,gsw_CH,gsw_LI,hi_,hi_IN,it_,it_CH,it_IT,ja_,ja_JP,nb_,nb_NO,nb_SJ,nl_,nl_NL,pl_,pl_PL,pt_,pt_AO,pt_BR,pt_CV,pt_GW,pt_MO,pt_MZ,pt_PT,pt_ST,pt_TL,ro_MD,ro_RO,rof_,ru_,ru_BY,ru_KG,ru_KZ,ru_MD,ru_RU,ru_UA,sv_,sv_AX,sv_FI,sv_SE,tr_,tr_CY,tr_TR,uk_,uk_UA,zh_,zh_CN,zh_HK,zh_MO,zh_SG,zu_,zu_ZA}
==> Locale to set for iOS (XCUITest driver only) and Android. fr_CA format for iOS. CA format (country name abbreviation) for Android (default = )
--tags TAGS ==> Feature(s) / Scenario(s) to be executed (separate tags by comma and without spaces)
--exclude {wip,skip,bug,slow,}
==> Feature(s) / Scenario(s) to be ignored / skipped from execution using a single tag (recommended: wip)
Finally, you can vary the command options such as these samples below and much more. If you does not pass the other arguments, it will be considered the default values:
python behave_runner.py --target local_emulation
python behave_runner.py --target local_emulation --os iOS --os_version '14.3' --device_name 'iPhone 12' --orientation Landscape --app_path'.resources\\mobile_automation\\Sample.ipa'
python behave_runner.py --target bs --mode native_app --os iOS --os_version '14.0' --device_name 'iPhone 11' --app_path '.resources\\mobile_automation\\Sample.ipa'
python behave_runner.py --target real_device --mode native_app --os Android --os_version '10.0' --device_name 'Samsung Galaxy A51' --tags login-sample --exclude slow
Install Appium Python Client in your local machine to make available the Appium web driver for mobile apps (emulated or real Android / iOS devices connected). Then, just run this Python script to install the Appium Server (check if the version number is presented at the end):
python appium_setup.py --server install
Open a separated terminal to start the Appium server. You have two ways to run it:
- Via
appium_setup.py
script, set the host and port if you need (by default it is "0.0.0.0" and "4723", respectively):
python appium_setup.py --server start
python appium_setup.py --server start --localhost <YOUR_HOST> --port <YOUR_PORT>
- Or you can execute directly with:
appium --address <host> --port <number>
To inspect the device elements in the Appium Client during test implementation, make sure if you have an Appium Desktop. You can download directly from http://appium.io/ Additionally, you need to install Java to make available the Appium client https://java.com/en/download
- Set the environment variable Path for JAVA_HOME:
export JAVA_HOME=$(/usr/libexec/java_home)
- Use
$echo ANDROID_HOME
and$echo JAVA_HOME
to get values from environment variables and set them in 'Edit Configurations' screen. - If you want to do this more than once, use the script
appium_setup.py
.
If you don't have any iPhone device with you, so you can use the XCode to emulate one. But first is necessary to clone the mobile application project to be tested with.
Follow these steps below (commands for MacOS / Linux) to setup the main resources such as Ruby:
- Install HomeBrew to facilitates the installation for any packages that Linux and MacOS are not able to do.
/bin/bash -c “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)
You can install Ruby in different ways. To prevent conflicts and protected Ruby folders, it's recommended to install it using RVM.
brew install gnupg
gpg --keyserver hkp://pool.sks-keyservers.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
\curl -sSL https://get.rvm.io | bash -s stable
echo "source $HOME/.rvm/scripts/rvm" >> ~/.bash_profile
rvm list
# No rvm rubies installed yet. Try 'rvm help install'.
Try a version such as 2.7.1:
rvm install 2.7.1
Check which ruby version available and if is properly installed:
rvm list
rvm alias create default 2.7.1
RVM should now load whenever you open a new shell. This can be tested by executing the following command which should output rvm is a function as shown below.
type rvm | head -n 1
Just check the versions available:
rvm list known
Then, you can switch to your desired version:
rvm install 2.6.3
rvm use 2.6.3
rvm use system
rvm alias create default 2.6.3
ruby -v
Install Ruby RBenv using brew and set it to version 2.6.5:
brew install ruby
brew install rbenv
rbenv init
rbenv rehash
rbenv install 2.6.5
rbenv global 2.6.5
eval "$(rbenv init -)"
ruby -v
curl -fsSL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-doctor | bash
- Export the Ruby Path (check the version first) if is not possible to run
ruby -v
, for example:
export PATH="/usr/local/opt/ruby/bin:/usr/local/lib/ruby/gems/3.0.0/bin:$PATH"
echo 'export PATH="/usr/local/opt/ruby/bin:$PATH"' >> ~/.bash_profile
source ~/.bash_profile
- Install Rails to manage the server-side application:
gem install rails
Download and install the XCode from Mac App Store. Just make sure that your XCode.app
is located at "/Applications" folder, otherwise you would see an error such as:
An unknown server-side error occurred while processing the command. Original error: Could not determine iOS SDK version: Could not get Xcode version. /Library/Developer/Info.plist does not exist on disk.
If you continue facing this issue, perhaps you will need to set the correct path from where the Xcode.app is being executed. For example, run this command to find the location:
xcrun --sdk macosx --show-sdk-path
To switch the SDK reference for Xcode, use this command:
xcode-select --switch /Applications/
Now, with a mobile app source in a local repository, try to open it using XCode and execute the following commands at the terminal to install the Ruby Gems (dependencies):
gem install bundler
bundle install
Install Carthage to help you in managing dependencies of dependencies in a Cocoa application. Finally, try to open the project via command line:
brew install carthage
brew update && brew upgrade carthage
open <YOUR_APP_NAME>.xcworkspace
If you need to update the dependencies before build any App project cloned into your local machine, it's very important to execute some commands to prevent build errors and clean cached files.
- Clear any cached generated by older project builds:
rm -rf ~/Library/Developer/Xcode/DerivedData/
- So first open a terminal, and navigate to the App repository. Then update dependencies to Pod:
cd /Users/<your_pc_user_name>/<path_to_repo>/<local_app_project>
bundle exec pod install
To see more information about, please, use or check the script setup_local_ios_project.py
.
Now you are able to emulate any App using XCode Simulator. Just keep in mind these steps:
- Select the SCHEME in the XCode Simulator
- Use the shortkey 'CMD + R' to emulate the app in a device chosen
- At XCode Project Navigator view, select the app in folder where it was build". Then, copy the Full Path presented in File Inspector. This will be useful to set the
mobile_app_path
property into theenv_settings.properties
later.
If you need to execute the tests externally in a CI Server like Bitrise, you will need to install Fastlane to run it locally and evaluate the FastFile script. So, first install Fastlane using the command below to prevent permission to writeblocks during the installation
sudo gem install fastlane -n /usr/local/bin
fastlane -v
Once installed Fastlane, you can run FastFile locally by this command:
fastlane ios pyon_ui_tests
If you are facing errors during Fastlane executiong, try to check the log and if you have rspec
missed, just try to install this Gem with:
gem install rspec --user
You will need at least the Android Debug Bridge (ADB) to help with test case implementations and debug the app. So follow these steps below:
- Install HomeBrew:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
- Install ADB:
brew cask install android-platform-tools
- Export the environment variable Path:
export ANDROID_HOME="Users/<PC_USER_NAME>/Library/Android/sdk
export PATH="${PATH}:/$ANDROID_HOME/platform-tools:/$ANDROID_HOME/tools:/$ANDROID_HOME/tools/bin"
- Start using
adb
.
The Behaviour Driven Development can make our automated tests much more agile, productive, sustainable and with a living-documentation of business. Considering this, in the following sections will be presented a step-by-step about how to implement a simple scenario considering Python-Behave (library backed up by Python code - Cucumber-based) and Selenium to make possible to automate our Gherkin scenarios.
Considering that the number of tests can increase significantly in this project, it is very important to keep in mind that you also need to have a good and coherent organisation of files, scenarios, features and settings associated to the tests. Initially, to have the codes recognised by Behave framework, all the files related to test cases should be implemented into the features
folder. Take a look at the recommended structure below.
All the tests are documented in Gherkin, a structured and natural language with properly keywords (Given, When, Then) that allows us to write testable specifications. Those files have the format .feature
and should be organised into the '/features' with subfolders such as ENVIRONMENT FOLDER (dev/staging/production) > DOMAIN FOLDER (global name of a functionality) > FEATURE FILE. For example:
features
└─── feature_domains
└─── staging
│ automation_sample_login.feature
| ...
production
└─── ...
With this, you could create a simple scenario that validates if user can search a content in the app. You just need to use the keywords with Feature:
, Background:
, Scenario:
, and describe the behaviours for steps with Given
, When
and Then
:
@login-sample
Feature: Automation Sample App
Scenario: Login the user with its credentials
Given that app is open at Login page
When user provides their wrong credentials
Then user sees "Wrong username or password"
As you could see, add a tag (started with @) trying to choose an easy and intuitive name that reminds you about the Feature. Also, you can include another tag above the scenario, if you want to create new scenarios into the same file. This can make easier to call specific scenarios or an entire feature to be executed via Behave command line.
After having a scenario defined, make sure that development_mode
is false
in env_settings.properties
if you want to execute the python3 behave_runner.py --tags login-sample
in the terminal (or set development_mode
to true
and include the tag app-login
to property debug_behave_tags
). Then, copy the snippet definitions generated automatically in console. You will need to implement your steps using them, like these:
You can implement step definitions for undefined steps with these snippets:
@given(u'that app is open at Login page')
def step_impl(context):
raise NotImplementedError(u'STEP: Given that app is open at Login page')
@when(u'user provides their wrong credentials')
def step_impl(context):
raise NotImplementedError(u'STEP: When user provides their wrong credentials')
@then(u'user sees "Wrong username or password"')
def step_impl(context):
raise NotImplementedError(u'STEP: Then user sees "Wrong username or password"')
Copied the snippets, create a new Python file into the '/features/steps' folder with the same or similar name of your .feature
.
Try to increment the file name ending with *_steps.py
and place them in the steps
folder only (to be read by Behave framework).
features
└─── steps
| app_login_steps.py
...
Into this new Python file, you should import behave
library to take the advantages of Behave to your Step Implementation.
from behave import *
# Paste your snippets for steps...
Then, just paste your snippets from clipboard into the search_car_steps.py
.
from behave import *
@given(u'that app is open at Login page')
def step_impl(context):
raise NotImplementedError(u'STEP: Given that app is open at Login page')
@when(u'user provides their wrong credentials')
def step_impl(context):
raise NotImplementedError(u'STEP: When user provides their wrong credentials')
@then(u'user sees "{error}"')
def step_impl(context):
raise NotImplementedError(u'STEP: Then user sees "Wrong username or password"')
Now, you have a basic structure using Behave, but the Steps have no code with the significant actions to cover the behaviour expected in the descriptions. To make this possible, all the interactions with HTML pages might be implemented using Appium/Selenium web driver, coded in Python. So, it is recommended a design pattern such as Page Objects to manage, reuse and store all the locators extracted from a functionality in mobile screen.
Additionally, considering that you will have many app pages to interact in your scenarios, it is very important to let them organised, distiguished by folders and subfolders as well.
In this case, create a file names ending with *_page.py
and put them into a folder containing the APP NAME (or a macro app module) > FUNCTIONALITY NAME (or feature name) > PYTHON PAGE OBJECT, like this sample:
features
└─── pages
└─── app_sample
│ auth_page.py
│ home_page.py
...
At the '/features/pages/' folder, create a new page object class that inherits the BaseAppPage module (from driver_wrappers.appium.native_app_wrapper import BaseAppPage
):
from driver_wrappers.appium.native_app_wrapper import BaseAppPage
from appium.webdriver.common.mobileby import MobileBy as MBy
class HomePage(BaseAppPage):
# ... declare the locators and Appium methods here
Through BaseAppPage, you can take all advantages from default Selenium web driver (to click, type text, etc.) and also consume dozen of wrapped methods customised from the most common component actions identified in an application (get text from an element, select a dropdown option, swipe and many other actions):
self.wait_for_element(by, location, with_text, title, is_visible, is_not_visible, is_clickable, is_selected, is_frame, is_alert, is_presented, typing_secs, handle_timeout)
self.get_element_by(by_type, element_location)
self.get_element_text(by_type, element_location, is_visible)
self.type_text(input_text, by_type, element_location, is_clickable)
self.click_on(by_type, element_location, is_visible)
self.click_on_element_by_accessibility_id(element_location)
# ... and many others
Considering this, extract the element locators inspecting the application's page opened in Appium Desktop and place them into the variables of your Page Object class. But, you will need to import from appium.webdriver.common.mobileby import MobileBy
into the HomePage, to define a kind of locator for a XCUITest element should be able to interpret (MBy.XPATH, MBy.ACCESSIBILITY_ID, By.IOS_UIAUTOMATION, etc.):
from driver_wrappers.appium.native_app_wrapper import BaseAppPage
from appium.webdriver.common.mobileby import MobileBy as MBy
class AuthPage(BaseAppPage):
loc_lbl_title = (MBy.XPATH, '//android.widget.FrameLayout[1]/android.view.ViewGroup/android.widget.TextView')
loc_txt_username = (MBy.ID, 'com.dgotlieb.automationsample:id/userName')
loc_txt_password = (MBy.ID, 'com.dgotlieb.automationsample:id/userPassword')
loc_btn_login = (MBy.ID, 'com.dgotlieb.automationsample:id/loginButton')
loc_lbl_error_message = (MBy.ID, 'com.dgotlieb.automationsample:id/errorTV')
The locator declared with a tuple ((MBy.<TYPE>, "<location string>")
) can be called directly using asterisk before a self.loc_name
.
To create validation methods for the steps when is necessary (mainly in the @Then
step), you should use the existing assert methods already invoked by BaseAppPage. So, you are able to call them directly into the page used by a scenario. Just define the asserts like these:
self.assert_that("<FOUND STRING IN PAGE>").is_equals_to("<EXPECTED STRING>", "<OPTIONAL DESCRIPTION>")
self.assert_that("<FOUND STRING IN PAGE>").contains_the("<EXPECTED STRING>", "<OPTIONAL DESCRIPTION>")
self.assert_that("<FOUND STRING IN PAGE>").is_different_from("<EXPECTED STRING>", "<OPTIONAL DESCRIPTION>")
self.assert_that(<FOUND NUMBER IN PAGE>).is_greater_than(b_value=<NUMBER>, "<OPTIONAL DESCRIPTION>")
self.assert_that(<FOUND NUMBER IN PAGE>).is_less_than(b_value=<NUMBER>, "<OPTIONAL DESCRIPTION>")
self.assert_that(<FOUND NUMBER IN PAGE>).is_between_the(expected_min=<NUMBER>, expected_max=<NUMBER>, "<OPTIONAL DESCRIPTION>")
self.assert_that().is_in_pdf("<PDF FILE PATH OR URL>", "<EXPECTED STRING>", "<OPTIONAL DESCRIPTION>")
Then, you should have a page with an implementation like that:
class AuthPage(BaseAppPage):
loc_lbl_title = (MBy.XPATH, '//android.widget.FrameLayout[1]/android.view.ViewGroup/android.widget.TextView')
loc_txt_username = (MBy.ID, 'com.dgotlieb.automationsample:id/userName')
loc_txt_password = (MBy.ID, 'com.dgotlieb.automationsample:id/userPassword')
loc_btn_login = (MBy.ID, 'com.dgotlieb.automationsample:id/loginButton')
loc_lbl_error_message = (MBy.ID, 'com.dgotlieb.automationsample:id/errorTV')
def check_title(self):
self.is_the_element_presented(*self.loc_lbl_title)
def type_input_username(self, input_value):
self.wait_for_element(*self.loc_txt_username)
# self.click_on(*self.loc_txt_username)
self.type_text(input_value, *self.loc_txt_username)
def type_input_password(self, input_value):
self.wait_for_element(*self.loc_txt_password)
self.type_text(input_value, *self.loc_txt_password)
def click_on_login(self):
self.click_on(*self.loc_btn_login)
def validate_error_message(self, message):
message_found = self.get_element_text(*self.loc_lbl_error_message)
self.assert_that(message_found).contains_the(value_expected=message, optional_description="Login validation message")
Having all the pages needed already implemented, you need to call the methods to satisfy the scenario behaviour, as well the validations.
from behave import *
from features.pages.app_sample.auth_page import AuthPage
login_page = AuthPage(object)
@given('that app is open at Login page')
def step_given_that_app_is_open_at_login_page(context):
login_page.check_title()
@when('user provides their wrong credentials')
def step_when_user_types_text_to_search(context):
login_page.type_input_username("wrong_user_name")
login_page.type_input_password("wrong_pass_123")
@then('user sees "{error}"')
def step_then_the_content_related_is_found(context, error):
login_page.validate_error_message(message=error)
And your first test case scenario is ready to be executed for the first time!
Regardless if you are using the debug mode to execute tests or triggering them via CI server, you should set the tags accordingly declaring with or without @
, but separating them by comma and without spaces. See these examples:
You can combine TAGS like these examples:
-
e.g. 1) ISOLATED SCENARIO:
demo-app-login
-
e.g. 2) COMBINING SCENARIOS:
demo-app-login,demo-app-search,...
-
e.g. 3) CALLING ENTIRE FEATURES:
login-sample
If you leave the parameter related to tags empty, all the features from the environment selected will be executed regardless if is set by properties or by command line.
If you need to manage or maintain the CI/CD files for PyonUIT, just keep in mind about the following structure.
- JENKINS (Both: iOS and Android): Create all files for environment provisioning, considering the fixtures implemented. Then, create scripts or reuse the existing ones following the steps showed previously in this document. Finally, call the tests in the same way as
run_behave.sh
file. - BITRISE (iOS only): Create a Workflow in the Bitrise, integrating the necessary build steps. You need to consider the
.fastlane/Fastfile
as a last Workflow step into the Workflow configuration. If you need to install Fastlane, follow the README.md in the same folder.fastlane/Fastfile
.