Comprehensive Automated Testing for Python Web Applications

by | Python

Introduction to Web Application Testing

Overview

Web application testing is crucial to ensure that your application performs well across different scenarios, platforms, and user interactions. This section introduces you to automated testing using Python for web applications. By the end of this unit, you will have a functional environment ready for writing and executing automated tests.

Setup Instructions

1. Install Required Tools

Ensure you have Python installed. You will need additional packages to handle web automation and testing.

pip install selenium pytest

The selenium package allows you to control the web browser programmatically, while pytest helps in organizing and running test cases.

2. WebDriver Setup

Selenium requires a WebDriver for browser automation. Below are the steps to set up ChromeDriver. You can replace it with the WebDriver for your browser of choice.

  • Download ChromeDriver: ChromeDriver
  • Add ChromeDriver to PATH: Ensure the downloaded chromedriver executable is located in a directory included in your system’s PATH environment variable.

3. Basic Project Structure

Organize your project directory properly for clarity and easier management of files.

webapp_testing/
?
??? tests/
?    ??? __init__.py
?    ??? test_login.py
?
??? pages/
?    ??? __init__.py
?    ??? login_page.py
?
??? conftest.py
??? requirements.txt
??? README.md

4. Creating Your First Test: Login Test

Page Object Model (POM)

Separate the concerns using the Page Object Model. Here, we create a class for the login page where we define all interactions.

File: pages/login_page.py

from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys

class LoginPage:
    def __init__(self, driver):
        self.driver = driver
        self.username_input = (By.NAME, "username")  # Replace with actual locators
        self.password_input = (By.NAME, "password")  # Replace with actual locators
        self.login_button = (By.XPATH, "//button[@type='submit']")  # Replace with actual locators

    def enter_username(self, username):
        self.driver.find_element(*self.username_input).send_keys(username)

    def enter_password(self, password):
        self.driver.find_element(*self.password_input).send_keys(password)

    def submit(self):
        self.driver.find_element(*self.login_button).click()

Test Case

Define the test case using pytest.

File: tests/test_login.py

import pytest
from selenium import webdriver
from pages.login_page import LoginPage

@pytest.fixture
def driver():
    options = webdriver.ChromeOptions()
    options.add_argument('--headless')  # run tests in headless mode
    driver = webdriver.Chrome(options=options)
    driver.implicitly_wait(10)
    yield driver
    driver.quit()

def test_valid_login(driver):
    login_url = "http://example.com/login"  # Replace with actual login URL
    driver.get(login_url)

    login_page = LoginPage(driver)
    login_page.enter_username("testuser")
    login_page.enter_password("securepassword")
    login_page.submit()

    assert "Dashboard" in driver.title  # Replace with actual validation

5. Running the Tests

With everything set up, you can now run your tests using the pytest command:

pytest

This command will search for test_*.py files in your project, execute the test cases, and present a summary of test results.

Conclusion

Following these instructions, you have set up your environment for web application testing with a practical example of a login functionality test. You can extend this by adding more tests, such as form submissions and navigation checks, using a similar approach.

Setting Up Python Testing Environments

This guide walks you through setting up a Python testing environment to develop automated test scripts for web applications. The environment will support functionalities like login, form submissions, and navigation using a Python testing framework.

Step 1: Project Structure

First, create a project directory with the following structure:

web_app_test/
??? tests/
?   ??? __init__.py
?   ??? test_login.py
?   ??? test_form_submission.py
?   ??? test_navigation.py
??? pages/
?   ??? __init__.py
?   ??? login_page.py
?   ??? form_page.py
?   ??? navigation_page.py
??? utilities/
?   ??? __init__.py
?   ??? driver.py
??? requirements.txt
??? conftest.py

Step 2: Installing Dependencies

Add required libraries to requirements.txt:

pytest
selenium

Install the requirements:

pip install -r requirements.txt

Step 3: Web Driver Setup

Create a utilities/driver.py file to manage the WebDriver instance:

from selenium import webdriver

class Driver:
    _driver = None

    @classmethod
    def get_driver(cls, browser="chrome"):
        if cls._driver is None:
            if browser == "chrome":
                cls._driver = webdriver.Chrome()
            elif browser == "firefox":
                cls._driver = webdriver.Firefox()
            else:
                raise ValueError(f"Unsupported browser: {browser}")
            
            cls._driver.implicitly_wait(10)
        return cls._driver

    @classmethod
    def quit_driver(cls):
        if cls._driver is not None:
            cls._driver.quit()
            cls._driver = None

Step 4: Page Object Model (POM)

Create page classes:


  • pages/login_page.py:


    from selenium.webdriver.common.by import By

    class LoginPage:
    def __init__(self, driver):
    self.driver = driver
    self.username_input = driver.find_element(By.ID, "username")
    self.password_input = driver.find_element(By.ID, "password")
    self.login_button = driver.find_element(By.ID, "login")

    def login(self, username, password):
    self.username_input.send_keys(username)
    self.password_input.send_keys(password)
    self.login_button.click()


  • pages/form_page.py:


    from selenium.webdriver.common.by import By

    class FormPage:
    def __init__(self, driver):
    self.driver = driver
    self.form_input = driver.find_element(By.ID, "form-input")
    self.submit_button = driver.find_element(By.ID, "submit")

    def submit_form(self, data):
    self.form_input.send_keys(data)
    self.submit_button.click()


  • pages/navigation_page.py:


    from selenium.webdriver.common.by import By

    class NavigationPage:
    def __init__(self, driver):
    self.driver = driver
    self.nav_link = driver.find_element(By.ID, "nav-link")

    def navigate(self):
    self.nav_link.click()

Step 5: Test Cases

Create test cases:


  • tests/test_login.py:


    import pytest
    from utilities.driver import Driver
    from pages.login_page import LoginPage

    @pytest.fixture(scope="module")
    def setup():
    driver = Driver.get_driver()
    driver.get("http://example.com/login")
    yield driver
    Driver.quit_driver()

    def test_login_success(setup):
    login_page = LoginPage(setup)
    login_page.login("valid_user", "valid_password")
    assert "Dashboard" in setup.title # Example assertion


  • tests/test_form_submission.py:


    import pytest
    from utilities.driver import Driver
    from pages.form_page import FormPage

    @pytest.fixture(scope="module")
    def setup():
    driver = Driver.get_driver()
    driver.get("http://example.com/form")
    yield driver
    Driver.quit_driver()

    def test_form_submission(setup):
    form_page = FormPage(setup)
    form_page.submit_form("test data")
    assert "Form Submitted" in setup.page_source # Example assertion


  • tests/test_navigation.py:


    import pytest
    from utilities.driver import Driver
    from pages.navigation_page import NavigationPage

    @pytest.fixture(scope="module")
    def setup():
    driver = Driver.get_driver()
    driver.get("http://example.com")
    yield driver
    Driver.quit_driver()

    def test_navigation(setup):
    nav_page = NavigationPage(setup)
    nav_page.navigate()
    assert "Next Page" in setup.title # Example assertion

Step 6: Configuration File

Create conftest.py for shared fixtures if needed. Example:

import pytest
from utilities.driver import Driver

@pytest.fixture(scope="session", autouse=True)
def driver_setup(request):
    driver = Driver.get_driver()
    request.addfinalizer(Driver.quit_driver)
    return driver

Step 7: Running Tests

Run your tests using pytest:

pytest

This comprehensive setup should help you develop automated test scripts for web applications using Python. The setup ensures robust testing of functionalities such as login, form submissions, and navigation.

Automating Login Functionality Tests

Test Script for Login Functionality

This section provides a practical implementation of automating login functionality tests using Python. We will use Selenium, a powerful tool for controlling web browsers through programs and performing browser automation.

Import Required Libraries

Make sure you have Selenium installed (pip install selenium).

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import unittest

Define the Test Class

class LoginTest(unittest.TestCase):

    def setUp(self):
        self.driver = webdriver.Chrome()  # Assumes ChromeDriver is in PATH
        self.driver.get("https://your-web-application.com/login")

    def test_login_success(self):
        driver = self.driver

        # Locate username, password fields and login button and perform actions
        username_field = driver.find_element(By.ID, "username")
        password_field = driver.find_element(By.ID, "password")
        login_button = driver.find_element(By.ID, "loginButton")

        # Input credentials and login
        username_field.send_keys("validUsername")
        password_field.send_keys("validPassword")
        login_button.click()

        # Wait for the dashboard or some element to confirm successful login
        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.ID, "dashboard"))
        )

        # Verify login success
        self.assertIn("Dashboard", driver.title)

    def test_login_failure_invalid_password(self):
        driver = self.driver

        # Locate username, password fields and login button and perform actions
        username_field = driver.find_element(By.ID, "username")
        password_field = driver.find_element(By.ID, "password")
        login_button = driver.find_element(By.ID, "loginButton")

        # Input credentials and attempt to login
        username_field.send_keys("validUsername")
        password_field.send_keys("invalidPassword")
        login_button.click()

        # Wait for the error message
        error_message = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.ID, "errorMessage"))
        )

        # Verify error message is displayed
        self.assertEqual(error_message.text, "Invalid username or password")

    def tearDown(self):
        self.driver.quit()


if __name__ == "__main__":
    unittest.main()

Explanation

  • Libraries and Modules: We import necessary modules such as webdriver, unittest, and expected_conditions.
  • Test Class:LoginTest class inherits unittest.TestCase.
    • setUp: Initializes the web driver and navigates to the login page.
    • test_login_success: Tests the scenario where the login is successful with valid credentials.
    • test_login_failure_invalid_password: Tests the scenario where the login fails due to an invalid password.
    • tearDown: Quits the web driver after each test method runs.

Usage

Save the script in a file (e.g., test_login.py) and run it:

python test_login.py

This script will execute the test cases and provide test results, indicating whether the login functionality works as expected.

Automating Form Submission Tests

To automate form submission tests in a web application using Python, we can use the selenium library. The following implementation demonstrates how to create a test script to automate filling out and submitting a form.

Implementation

First, ensure you have the selenium library installed:

pip install selenium

Next, use the following script to automate form submission tests:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# Define the form submission test
def test_form_submission():
    # Initialize WebDriver (assuming you have ChromeDriver installed and added to PATH)
    driver = webdriver.Chrome()

    try:
        # Navigate to the form page
        driver.get("http://example.com/form-page")

        # Fill out the form fields (adjust IDs and values as per your form)
        name_input = driver.find_element(By.ID, "name")
        name_input.send_keys("John Doe")

        email_input = driver.find_element(By.ID, "email")
        email_input.send_keys("john.doe@example.com")

        message_input = driver.find_element(By.ID, "message")
        message_input.send_keys("This is a test message.")

        # Submit the form
        submit_button = driver.find_element(By.ID, "submit")
        submit_button.click()

        # Wait for the response page to load and display the result
        WebDriverWait(driver, 10).until(
            EC.text_to_be_present_in_element((By.ID, "success-message"), "Form submitted successfully!")
        )

        # Verify if form submission was successful
        success_message = driver.find_element(By.ID, "success-message").text
        assert success_message == "Form submitted successfully!"

        print("Form submission test passed!")

    except Exception as e:
        print(f"Form submission test failed: {e}")
    
    finally:
        # Close the browser
        driver.quit()

# Execute the test
if __name__ == "__main__":
    test_form_submission()

Explanation

  1. Driver Initialization: The script initializes the webdriver for Chrome.
  2. Navigation to Form Page: The browser navigates to the specified form URL.
  3. Form Filling: It locates the form elements by their IDs (name, email, message) and fills them with the given values.
  4. Form Submission: The form is submitted by clicking the submit button.
  5. Waiting for Response: The script waits for a success message to appear on the response page.
  6. Validation: The success message is checked to validate if the form was submitted correctly.
  7. Browser Closure: The browser is closed at the end of the test.

With this implementation, you can quickly integrate form submission tests into your automated test suite.

Note

Modify the URL, IDs of form elements, and the success message according to the actual details of your web application.

This approach covers essential aspects of form submission testing using Selenium in Python, ensuring that the form submission functionality works as expected in your web application.

Automating Navigation and Functional Testing in Python

Below is the Python implementation to automate navigation and functional testing for a web application using Selenium.

Prerequisites

Make sure you have selenium installed in your environment:

pip install selenium

Example: Automated Navigation and Functional Testing

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import unittest

class WebAppTest(unittest.TestCase):

    def setUp(self):
        self.driver = webdriver.Chrome()  # Ensure the correct path to your driver
        self.driver.get("http://example.com")  # Replace with your application URL

    def test_navigation_and_functionality(self):
        driver = self.driver
        
        # Navigate to a specific page by clicking a link
        link = driver.find_element(By.LINK_TEXT, "Some Link Text")
        link.click()

        # Wait for the page to load and check the title
        WebDriverWait(driver, 10).until(EC.title_contains("Expected Page Title"))
        self.assertIn("Expected Page Title", driver.title)

        # Perform an action on the new page (e.g., click a button)
        button = driver.find_element(By.ID, "button_id")
        button.click()

        # Wait for functionality to complete and validate results
        WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.ID, "result_id")))
        result_element = driver.find_element(By.ID, "result_id")
        self.assertEqual(result_element.text, "Expected Result Text")

    def tearDown(self):
        self.driver.quit()

if __name__ == "__main__":
    unittest.main()

Explanation

  1. Set Up:

    • Initialize the WebDriver for Chrome (or any browser you are using) and navigate to the application’s URL.
  2. Test Navigation and Functionality:

    • Find the link by its text and click it.
    • Wait until the new page’s title contains the expected string to ensure it has loaded.
    • Assert that the title is as expected.
    • Find a button by its ID and click it.
    • Wait until the desired result element is visible.
    • Verify the text of the result element to ensure the functionality works as expected.
  3. Tear Down:

    • Ensure the WebDriver quits after the test.

Use this script by running it within your Python environment. Ensure WebDriver is set up and configured correctly for the respective browser used in your tests.

Conclusion

This example outlines a clear and practical approach to automated navigation and functional testing using Python and Selenium. Integrate it into your project to ensure robust coverage of crucial functionalities.

Integrating with Testing Frameworks and CI/CD Pipelines

This section describes how to integrate automated test scripts with common testing frameworks and CI/CD pipelines using Python. Here, we’ll cover integrating with unittest or pytest frameworks and automating the process in a CI/CD environment using GitHub Actions.

1. Writing Tests

Assuming the tests are already written with unittest or pytest. Here’s an example of a pytest test file (test_webapp.py):

def test_login_functionality():
    # Code to test login functionality.
    assert login_successful

def test_form_submission():
    # Code to test form submission.
    assert form_submitted_correctly

def test_navigation():
    # Code to test navigation functionality.
    assert navigation_successful

2. Adding a pytest.ini Configuration File (if using pytest)

# pytest.ini

[pytest]

minversion = 6.0 addopts = -ra -q testpaths = tests

3. Setting Up the CI/CD Pipeline with GitHub Actions

Create a GitHub Actions workflow (.github/workflows/ci.yml) to run tests automatically on every push or pull request.

name: CI

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: '3.9'

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install pytest
          pip install -r requirements.txt

      - name: Run tests
        run: |
          pytest

4. Running Tests Locally (for verification before pushing)

To run pytest locally, simply run the following in your project directory:

pytest

Summary

By integrating the automated test scripts using pytest, and configuring a straightforward CI/CD pipeline via GitHub Actions, we ensure that tests are run automatically on each push or pull request. This setup helps to automatically verify the robustness of functionalities such as login, form submissions, and navigation regularly.

Related Posts