Monday 22 March 2021

Project Overview: Automated Web Application Testing Framework

This project involves the development of an automated testing framework for a web-based application. The framework will be built using Python, Pytest, and the Selenium library. The application will be tested for functional, regression, and integration testing.

Project Plan:

Understanding the Requirements:

The first step is to understand the requirements of the web-based application that needs to be tested. This includes the user interface, functionalities, and the scope of the testing. Based on this, the testing scenarios will be created.

Setting up the Testing Environment:

The next step is to set up the testing environment. This includes installing the necessary tools like Python, Pytest, and Selenium, as well as configuring the environment for automation testing.

Creating Test Cases:

Based on the requirements, test cases will be created. These test cases will be designed to cover all the features and functionalities of the application. These test cases will be prepared from the provided use cases (requirement) documents.

Developing Automation Scripts:

Once the test cases are created, automation scripts will be developed using Python and Pytest. The scripts will be designed to execute the test cases automatically and report the results.

Developing Automation Framework:

A Keyword Driven and Hybrid Driven automation framework will be designed and developed. The framework will provide a reusable and maintainable structure for the automation scripts.

Developing End-to-End Automation:

The automation scripts will be designed to cover the End-to-End testing of the application. This includes testing of all the features and functionalities of the application.

Functional Testing UAT:

The automated tests will be executed on different platforms using Selenium Webdriver and Pytest framework. This will include functional testing of UAT.

Designing Pytest Framework:

The Pytest framework will be designed to provide a powerful and flexible testing environment.

Behaviour Driven Development:

The knowledge of Behaviour Driven Development (BDD) will be utilized in developing the testing scenarios and the automation scripts.

Reporting and Analysis:

The test results will be reported, and the test analysis will be conducted. The analysis will help in identifying the areas of the application that need improvement.

Communication and Collaboration:

Good communication and collaboration with the development team and the customers will be maintained throughout the project.

Code Example:

Below is a sample code for automating the login functionality of the web application using Selenium and Pytest.

import pytest

from selenium import webdriver


class TestLogin:

    

    def setup_method(self):

        self.driver = webdriver.Chrome()

        self.driver.get("https://www.example.com")

    

    def teardown_method(self):

        self.driver.quit()

    

    def test_login(self):

        self.driver.find_element_by_name("username").send_keys("testuser")

        self.driver.find_element_by_name("password").send_keys("testpass")

        self.driver.find_element_by_name("login").click()

        assert self.driver.title == "Dashboard"


The above code uses the Pytest framework to create a test case for the login functionality of the web application. The setup_method and teardown_method methods are used to set up and tear down the testing environment respectively. The test_login method uses the Selenium library to automate the login process. It enters the username and password, clicks on the login button, and asserts that the title of the page after login is "Dashboard".

Additional Explanation:

The code above demonstrates the use of Pytest fixtures to set up the testing environment. The setup_method fixture is called before each test method, and it sets up the WebDriver object by launching a Chrome browser and navigating to the web application's login page.

The teardown_method fixture is called after each test method, and it quits the WebDriver object, ensuring that all browser instances are closed and any resources used during the test are released.

The test_login method uses the find_element_by_name method of the WebDriver object to locate the username, password, and login form elements on the page. The send_keys method is used to enter the test credentials, and the click method is used to submit the form.

Finally, the assert statement checks if the page title after login is "Dashboard". If the assertion fails, the test case will be marked as failed.

In conclusion, the project outlined above incorporates various skills required for manual and automated testing of web applications. The use of Python, Pytest, and Selenium provides a robust and flexible testing framework that can be adapted to different testing scenarios.

The project also highlights the importance of understanding the requirements, setting up the testing environment, creating test cases, developing automation scripts, and analyzing the test results. Good communication and collaboration with the development team and customers are also essential for ensuring the quality of the application under tight schedules.

Next, let's take a look at an example of how to implement keyword-driven automation using Python.

Keyword-driven automation is a technique that uses a set of keywords or actions to describe the desired behavior of the application. These keywords are mapped to specific functions or methods that perform the necessary actions.

Example of Keyword-Driven Automation:

For this example, let's consider a simple web application that allows users to register and login. The keywords that we will use for this application are "OpenBrowser", "Navigate", "EnterText", "ClickButton", and "VerifyText".

Here is an example of a keyword-driven automation script:

from selenium import webdriver def open_browser(): driver = webdriver.Chrome() return driver def navigate(driver, url): driver.get(url) def enter_text(driver, locator, text): element = driver.find_element_by_xpath(locator) element.clear() element.send_keys(text) def click_button(driver, locator): element = driver.find_element_by_xpath(locator) element.click() def verify_text(driver, locator, expected_text): element = driver.find_element_by_xpath(locator) actual_text = element.text assert actual_text == expected_text, f"Expected text: {expected_text}, Actual text: {actual_text}" def execute_keyword(driver, keyword, *args): if keyword == "OpenBrowser": return open_browser() elif keyword == "Navigate": navigate(driver, args[0]) elif keyword == "EnterText": enter_text(driver, args[0], args[1]) elif keyword == "ClickButton": click_button(driver, args[0]) elif keyword == "VerifyText": verify_text(driver, args[0], args[1]) else: raise ValueError(f"Invalid keyword: {keyword}") def execute_test_case(driver, test_case): for step in test_case: keyword = step[0] args = step[1:] execute_keyword(driver, keyword, *args) # Sample Test Case test_case = [ ("OpenBrowser",), ("Navigate", "https://example.com"), ("EnterText", "//input[@name='username']", "testuser"), ("EnterText", "//input[@name='password']", "testpass"), ("ClickButton", "//button[@type='submit']"), ("VerifyText", "//h1", "Welcome to Example.com"), ] driver = execute_test_case(driver, test_case)



In this script, we define functions for each keyword action, such as open_browser(), navigate(), enter_text(), click_button(), and verify_text(). We also define a execute_keyword() function that maps each keyword to its corresponding function.

The execute_test_case() function takes in a list of steps, where each step is a tuple that contains the keyword and any necessary arguments. It then iterates over each step and calls the execute_keyword() function to perform the desired action.

The sample test case provided logs in to a website by entering a username and password and then clicking the submit button. It then verifies that the page contains the expected text.

In conclusion, keyword-driven automation is a powerful technique for creating flexible and maintainable automation scripts. By mapping keywords to specific functions or methods, we can easily modify or extend our test cases without having to change the underlying code. This approach also enables non-technical stakeholders to contribute to the test automation effort by providing the necessary keywords or actions.


Now let's take a look at an example of how to implement behavior-driven development (BDD) using Python and the pytest-bdd library.

BDD is a technique that focuses on describing the desired behavior of the application in natural language that is easy for both technical and non-technical stakeholders to understand. BDD uses scenarios to describe the expected behavior of the application, and these scenarios are written in a format that is similar to natural language.

Example of BDD:

For this example, let's consider the same web application that allows users to register and login. We will use the pytest-bdd library to define our scenarios and steps.

Here is an example of a feature file that describes the behavior of the login functionality:

Feature: Login As a user I want to be able to login So that I can access my account Scenario: Successful login Given the login page is open When I enter my username and password And I click the login button Then I should see the welcome page Scenario: Invalid username or password Given the login page is open When I enter an invalid username or password And I click the login button Then I should see an error message



In this feature file, we define a feature called "Login" and two scenarios, one for a successful login and one for an invalid username or password. Each scenario consists of a set of steps, such as "Given the login page is open" and "When I enter my username and password".

We can then define our step definitions in a Python file using the pytest-bdd library:

from selenium import webdriver from pytest_bdd import given, when, then, scenario # Constants LOGIN_PAGE_URL = "https://example.com/login" WELCOME_PAGE_URL = "https://example.com/welcome" INVALID_CREDENTIALS_ERROR = "Invalid username or password" # Fixtures @scenario("login.feature", "Successful login") def test_successful_login(): pass @scenario("login.feature", "Invalid username or password") def test_invalid_credentials(): pass @given("the login page is open") def open_login_page(): driver = webdriver.Chrome() driver.get(LOGIN_PAGE_URL) return driver @when("I enter my username and password") def enter_credentials(open_login_page): username_field = open_login_page.find_element_by_name("username") password_field = open_login_page.find_element_by_name("password") username_field.send_keys("testuser") password_field.send_keys("testpass") @when("I enter an invalid username or password") def enter_invalid_credentials(open_login_page): username_field = open_login_page.find_element_by_name("username") password_field = open_login_page.find_element_by_name("password") username_field.send_keys("invaliduser") password_field.send_keys("invalidpass") @when("I click the login button") def click_login_button(open_login_page): login_button = open_login_page.find_element_by_xpath("//button[@type='submit']") login_button.click() @then("I should see the welcome page") def verify_welcome_page(open_login_page): assert open_login_page.current_url == WELCOME_PAGE_URL @then("I should see an error message") def verify_error_message(open_login_page): error_message = open_login_page.find_element_by_xpath("//div[@class='error']") assert error_message.text == INVALID_CREDENTIALS_ERROR



In this file, we define fixtures for each scenario and step definitions for each step in the scenarios. We use the @given, @when, and @then decorators to define step definitions that match the steps in the feature file.

We also define constants for the URLs and error message so that they can be easily reused throughout the tests.

Finally, we define test functions using the @scenario decorator and pass in the feature file and scenario name. This tells pytest-bdd which feature and scenario the test function corresponds to.

When we run our tests using pytest, pytest-bdd will automatically generate test cases for each scenario and run them using the step definitions that we have defined.

In addition to using BDD, we can also use the same pytest framework to write functional tests and automate them using Selenium WebDriver.

Example of Selenium Webdriver Test:

Let's consider the same login functionality example and write a Selenium Webdriver test for it. We will use the Page Object Model design pattern to organize our test code.

First, we define a LoginPage class that represents the login page of our web application:

from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC class LoginPage: URL = "https://example.com/login" USERNAME_FIELD = (By.NAME, "username") PASSWORD_FIELD = (By.NAME, "password") LOGIN_BUTTON = (By.XPATH, "//button[@type='submit']") def __init__(self, driver): self.driver = driver def open(self): self.driver.get(self.URL) def enter_credentials(self, username, password): username_field = WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located(self.USERNAME_FIELD)) password_field = WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located(self.PASSWORD_FIELD)) username_field.send_keys(username) password_field.send_keys(password) def click_login_button(self): login_button = WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located(self.LOGIN_BUTTON)) login_button.click() def get_error_message(self): error_message = WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CLASS_NAME, "error"))) return error_message.text


In this class, we define constants for the URLs and locators of the login page elements. We also define methods for opening the login page, entering credentials, clicking the login button, and getting the error message.

Next, we define a test function that uses the LoginPage class to test the login functionality:

from selenium import webdriver def test_login(): driver = webdriver.Chrome() login_page = LoginPage(driver) login_page.open() login_page.enter_credentials("testuser", "testpass") login_page.click_login_button() assert driver.current_url == "https://example.com/welcome" def test_invalid_credentials(): driver = webdriver.Chrome() login_page = LoginPage(driver) login_page.open() login_page.enter_credentials("invaliduser", "invalidpass") login_page.click_login_button() assert login_page.get_error_message() == "Invalid username or password"


In these test functions, we create a new instance of the LoginPage class and call its methods to simulate the user actions of entering credentials and clicking the login button. We then use assertions to verify that the user is redirected to the welcome page after a successful login and that an error message is displayed for invalid credentials.

When we run these tests using pytest, Selenium WebDriver will automate the browser and perform the user actions that we have defined in the LoginPage class.

By combining BDD and Selenium WebDriver, we can write tests that describe the desired behavior of our web application in natural language and automate those tests to ensure that the application behaves as expected.


In this project, we have demonstrated how to use manual and automated testing techniques to ensure the quality of web-based applications. We have also shown how to use the pytest-bdd framework to write BDD tests and the Selenium WebDriver library to automate functional tests.

By using BDD, we can describe the behavior of our application in a language that is easily understood by all stakeholders, including developers, testers, and business analysts. This helps to ensure that everyone is on the same page and that the application meets the requirements of the end-users.

By using Selenium WebDriver, we can automate functional tests and ensure that the application works as expected in different environments and browsers. This helps to catch bugs early in the development process and ensure that the application is stable and reliable.

Overall, manual and automated testing are essential parts of the software development life cycle, and they help to ensure that the application meets the needs of the end-users and is of high quality.

Types of testing

There are several types of testing that can be performed on software applications. Here are some of the most common types of testing:

Unit Testing: This is a type of testing in which individual units or components of the software application are tested in isolation from the rest of the application. The purpose of unit testing is to ensure that each individual unit functions as expected.

Integration Testing: This is a type of testing in which different units or components of the software application are tested together to ensure that they work correctly when integrated. The purpose of integration testing is to detect defects in the interaction between different units.

System Testing: This is a type of testing in which the entire software system is tested as a whole. The purpose of system testing is to ensure that the application meets the requirements and works as expected in the production environment.

Acceptance Testing: This is a type of testing in which the application is tested against the requirements provided by the client or end-user. The purpose of acceptance testing is to ensure that the application meets the expectations of the client or end-user.

Regression Testing: This is a type of testing in which previously tested functionality is retested after making changes or adding new features to the application. The purpose of regression testing is to ensure that the changes do not affect the existing functionality of the application.

Performance Testing: This is a type of testing in which the performance of the application is tested under different load conditions. The purpose of performance testing is to ensure that the application can handle the expected load and perform well under stress.

Security Testing: This is a type of testing in which the security of the application is tested to ensure that it is protected against unauthorized access, attacks, and other security threats.

These are just some of the many types of testing that can be performed on software applications. The type of testing required for a particular application depends on various factors, such as the requirements, the complexity of the application, the budget, and the timeline.

Usability Testing: This is a type of testing in which the application is tested for its user-friendliness and ease of use. The purpose of usability testing is to ensure that the application is intuitive and easy to use for the end-user.

Compatibility Testing: This is a type of testing in which the application is tested to ensure that it works correctly across different browsers, operating systems, and devices. The purpose of compatibility testing is to ensure that the application works consistently across different environments.

Exploratory Testing: This is a type of testing in which the tester explores the application to identify defects that may have been missed during other types of testing. The purpose of exploratory testing is to find defects that may not be found through other testing methods.

Ad-hoc Testing: This is a type of testing in which the tester performs testing without a predefined plan or script. The purpose of ad-hoc testing is to identify defects that may not be found through other testing methods and to provide feedback on the usability and user-friendliness of the application.

Localization Testing: This is a type of testing in which the application is tested to ensure that it is suitable for use in different regions and languages. The purpose of localization testing is to ensure that the application can be used by people from different regions and cultural backgrounds.

These are some of the most common types of testing performed on software applications. It is important to choose the right type of testing for your application to ensure that it meets the required quality standards and is suitable for its intended use.

Smoke Testing: This is a type of testing in which the most critical and basic functionalities of the application are tested to ensure that the application is stable enough to proceed with further testing. The purpose of smoke testing is to ensure that the application is ready for further testing.

Sanity Testing: This is a type of testing in which a limited set of test cases are executed to ensure that the most critical and high-priority functionalities of the application are working as expected after making changes or fixing defects. The purpose of sanity testing is to quickly verify that the application is stable enough to proceed with further testing.

A/B Testing: This is a type of testing in which two different versions of the application are tested simultaneously to see which version performs better in terms of user engagement, user retention, conversion rates, and other metrics. The purpose of A/B testing is to optimize the application for better user engagement and conversion rates.

End-to-End Testing: This is a type of testing in which the entire workflow of the application is tested from the user interface to the back-end system to ensure that the application works as expected from end-to-end.

Accessibility Testing: This is a type of testing in which the application is tested to ensure that it is accessible to people with disabilities, such as visual impairment, hearing impairment, and motor impairment. The purpose of accessibility testing is to ensure that the application can be used by people with different abilities.

Recovery Testing: This is a type of testing in which the application is tested to see how it recovers from failures, crashes, and other errors. The purpose of recovery testing is to ensure that the application can recover from unexpected failures and continue to function as expected.

These are some additional types of testing that can be performed on software applications. The choice of testing type depends on the application's requirements, complexity, and other factors.

Security Testing: This is a type of testing in which the application is tested to identify vulnerabilities and weaknesses that could be exploited by malicious attackers. The purpose of security testing is to ensure that the application is secure and can protect sensitive data and information.

Performance Testing: This is a type of testing in which the application is tested to ensure that it can handle a large number of users and requests without slowing down or crashing. The purpose of performance testing is to ensure that the application is scalable and can perform well under different loads and conditions.

Load Testing: This is a type of performance testing in which the application is tested to ensure that it can handle a large number of users and requests without crashing or slowing down. The purpose of load testing is to identify the application's maximum capacity and to ensure that it can handle heavy loads.

Stress Testing: This is a type of performance testing in which the application is tested to see how it behaves under extreme load and stress conditions. The purpose of stress testing is to identify the application's breaking point and to see how it recovers from failures.

Volume Testing: This is a type of performance testing in which the application is tested to ensure that it can handle a large volume of data without slowing down or crashing. The purpose of volume testing is to ensure that the application can handle large amounts of data without performance issues.

Scalability Testing: This is a type of performance testing in which the application is tested to see how it performs when the number of users or requests increases over time. The purpose of scalability testing is to ensure that the application can handle increasing loads and can scale up or down as needed.

These are some of the advanced types of testing that are performed on software applications to ensure their quality and performance. It is important to choose the right type of testing based on the application's requirements, complexity, and other factors.

Usability Testing: This is a type of testing in which the application is tested to ensure that it is user-friendly and easy to use. The purpose of usability testing is to identify any issues or problems with the user interface, navigation, and other user-related aspects of the application.

Localization Testing: This is a type of testing in which the application is tested to ensure that it can be used in different languages and cultures. The purpose of localization testing is to identify any issues or problems with the application's language, text, and other cultural aspects.

Compatibility Testing: This is a type of testing in which the application is tested to ensure that it can run on different hardware, software, and operating systems. The purpose of compatibility testing is to identify any issues or problems with the application's compatibility with different environments.

Installation Testing: This is a type of testing in which the application is tested to ensure that it can be installed and uninstalled without any issues or problems. The purpose of installation testing is to identify any issues or problems with the installation process of the application.

Recovery Testing: This is a type of testing in which the application is tested to see how it recovers from crashes, failures, and other errors. The purpose of recovery testing is to identify any issues or problems with the application's recovery mechanisms.

Exploratory Testing: This is a type of testing in which the tester explores the application to find defects and issues that may not be easily found through scripted testing. The purpose of exploratory testing is to identify any issues or problems with the application that may have been missed by other types of testing.

These are some of the common types of testing that are performed on software applications to ensure their quality and reliability. The choice of testing type depends on the application's requirements, complexity, and other factors.


Labels: ,

0 Comments:

Post a Comment

Note: only a member of this blog may post a comment.

<< Home