TAP is a simple test automation project written in python and aplying page object model. It uses Selenium as the automation framework and unittest library. The application used as the base for the tests is GitHub website.
The Page Object Model (POM) is a design pattern that creates an object repository for storing all web elements. When using POM you have the following benefits:
- Clean and more redable code of your tests since they are splited from the code of web elements manipulation
- Reduced maintenance since sometimes you just need to adjust things in page classes without touching the code of your tests
- More code reusage since new tests can use the same page classes
TAP is structured files distributed in 3 folders:
- pages: this folder contains all the files implementing the classes that represent the pages and the elements (fields, buttons, etc).
- testdata: this folder contains the class with all the values used in the testes
- tests: this folder contains the files with the tests properly saying.
All the classes that represent pages or page elements (fields, buttons, etc) are stored here. They contain properties representing parts of each page and also methods that are the actions the user can do in each page. The pages available are:
- Homepage: represents GitHub main page
- SearchResultPage: represents GitHub Search Results page
- UserPage: model for user page in GitHub
- UserRepoPage: model for GitHub User Repository page
All the pages where extended from BasePage. At the moment no properties or methods were added to this class, but it could be the case if we need a certain behavior in all the pages.
The BasePageElement is an extension of Selenium WebElement class with additional methods set_text(self,text), get_text() and hit_enter(self).
All the locators used to find fields, buttons or drop downs were added in classes stored in locators.py: HomepageLocators, SearchResultPageLocators, RepositorySearchLocators and UserRepoPageLocators.
The locators are defined as python tuples data type informing the type of the locator and the corresponding string. Here are some examples:
SEARCH_FIELD_LOCATOR = (By.NAME,'q')
REPO_SEARCH_FIELD_LOCATOR = (By.ID,'your-repos-filter')
LANGUAGE_FILTER_BUTTON_LOCATOR = (By.XPATH, '//*[@id="language-options"]/summary')
All the values used in the testes are represented as methods of the class TestData. For example, to store the url ot GitHub the property below was created:
GITHUB_URL = "https://github.com/"
This property is used in many other places (mainly page classes) and also to create more complex urls. The advantage of this technique is that if we need to change the url, we just need to chang in TestData class and all the other classes will use the new value.
At this point, there is only one file called tests.py with 2 classes:
- GitHubSearch: this class has 1 test over the Search by User in GitHub
- GitHubRepoSearch: this class has 2 tests on the Repository Search and filtering, starting from an user page
Python logging library was used to log information about the progress of each test.
To do that, first we need to import the library:
import logging
Then define the log level. In this case Information was used:
logging.basicConfig(level=logging.INFO)
Then logging.info was called each time it was interesting to inform some progress of the tests. For example:
def test_search_in_github(self):
logging.info('-----------------------------------------------')
logging.info('Starting to test search feature on GitHub')
logging.info('Loading github homepage')
home_page = homepage.Homepage(self.driver)
It's also interesting to note that the message added in each logging instruction also works as comments of the code.
First you need to clone the repository in your machine.
You need to have Selenium library. To install using pip: pip install selenium
More details here: https://selenium-python.readthedocs.io/installation.html
To run all the tests, from tap folder:
python test.py
You should see an output likes this, if all the tests passed:
To run just a specific test, assuming you already are in tests folder:
python test.py Class.Desired_test
For example:
python test.py GitHubRepoSearch.test_search_by_existing_repo_in_user_page
An interesting option was added: run the tests in headless mode, it means, without opening the browser.
To activate this option, you need to add an environment variable:
Linux: export TAP_HEADLESS=1
Windows: set TAP_HEADLESS=1
This option should work in both.
For testing purpose, a workflow was created using GitHub Action.
Its name is CI and its definition file is here: https://github.com/mauriciokobren/tap/blob/master/.github/workflows/main.yml
Basically it checks out the code in a Linux instance, install the dependencies and run the tests.
CI workflow is triggered every time a pull request agains master is created or when a commit in master is done.
Clicking on a specific build, you can see more details, something like the image below.
To see the steps of the run, just click on build. You should see something like the image below:
Maybe there is a better way to handle the import of modules stored in different folders. For example, in tests\test.py I need to import modules stored in pages folder. After some research on the internet, I found that the folder should be added in python path:
...
sys.path.append(os.path.abspath(os.path.join('..', 'pages')))
sys.path.append(os.path.abspath(os.path.join('..', '')))
from pages import homepage,userpage,userrepopage
...
The webdriver obejct is created in the setup() of test classes in tests/test.py. For now Firefox browser was chosed, but more browsers could be supported, like Chrome for example.
No screenshot or video is recorded when a test fails. This can be a good resource for analysis.