Software Testing Tutorial Unit Integration & E2E Testing

Zaheer Ahmad 5 min read min read
Python
Software Testing Tutorial Unit Integration & E2E Testing

Software testing is a critical skill for every software developer. In this software testing tutorial, we will explore unit testing, integration testing, and end-to-end (E2E) testing, explaining their importance, differences, and practical usage.

For Pakistani students, learning testing is crucial to build reliable apps, whether for a startup in Lahore, an e-commerce site in Karachi, or a fintech solution handling PKR transactions in Islamabad. Proper testing ensures that your software works as intended, reduces bugs, and improves your chances of success in real-world projects.

Prerequisites

Before diving into testing, you should have:

  • Basic knowledge of a programming language (Python, JavaScript, or Java)
  • Understanding of functions, classes, and modules
  • Familiarity with Git and version control for collaborative development
  • Basic awareness of software development lifecycle (SDLC)
  • A code editor like VS Code or PyCharm installed

Core Concepts & Explanation

What is Unit Testing?

Unit testing involves testing individual units or components of your software. A “unit” is the smallest testable part of your application, like a function or class method. Unit tests are fast, reliable, and isolated.

Example: Testing a function that calculates PKR to USD conversion.

def convert_to_usd(pkr_amount, rate):
    return pkr_amount / rate

# Unit Test
def test_convert_to_usd():
    pkr = 5000
    rate = 285
    expected = 17.54
    result = convert_to_usd(pkr, rate)
    assert round(result, 2) == expected

Explanation line by line:

  • def convert_to_usd(pkr_amount, rate): → Defines a function to convert PKR to USD.
  • return pkr_amount / rate → Performs conversion.
  • def test_convert_to_usd(): → Defines a unit test function.
  • pkr = 5000 → Example PKR amount.
  • rate = 285 → Exchange rate PKR → USD.
  • expected = 17.54 → Expected USD output.
  • result = convert_to_usd(pkr, rate) → Calls the function.
  • assert round(result, 2) == expected → Checks the output matches expectation.

What is Integration Testing?

Integration testing focuses on interactions between modules. It ensures that different components of your application work together as expected.

Example: Testing payment processing in an e-commerce app in Karachi.

def process_payment(user_id, amount, payment_gateway):
    user_balance = get_user_balance(user_id)
    if user_balance >= amount:
        result = payment_gateway.charge(amount)
        if result:
            deduct_balance(user_id, amount)
            return True
    return False

# Integration Test
def test_process_payment():
    user_id = "Ahmad123"
    amount = 2000
    payment_gateway = MockGateway(success=True)
    assert process_payment(user_id, amount, payment_gateway) == True

Explanation line by line:

  • process_payment(...) → Function integrating user balance check and payment gateway.
  • user_balance = get_user_balance(user_id) → Retrieves balance.
  • if user_balance >= amount: → Ensures enough funds.
  • result = payment_gateway.charge(amount) → Charges via gateway.
  • if result: deduct_balance(user_id, amount) → Deducts balance if payment successful.
  • return True/False → Returns status.
  • MockGateway(success=True) → Simulated gateway for test.

What is End-to-End (E2E) Testing?

E2E testing validates the entire workflow of an application, simulating real user behavior. These tests are slower but provide confidence that the system works from start to finish.

Example: Testing user registration and order placement for Fatima in Lahore.

describe('E2E Test: Place Order', () => {
  it('Registers user and places an order', () => {
    cy.visit('https://example.com')
    cy.get('#register').click()
    cy.get('#username').type('Fatima321')
    cy.get('#password').type('securePass123')
    cy.get('#submit').click()
    
    cy.get('#login').click()
    cy.get('#username').type('Fatima321')
    cy.get('#password').type('securePass123')
    cy.get('#loginButton').click()
    
    cy.get('#product-1').click()
    cy.get('#add-to-cart').click()
    cy.get('#checkout').click()
    cy.contains('Order Successful').should('exist')
  })
})

Explanation:

  • Uses Cypress for browser automation.
  • Visits site, registers user, logs in, adds product to cart, and checks out.
  • Confirms that the workflow completes successfully.

Practical Code Examples

Example 1: Unit Testing with AAA Pattern

The AAA (Arrange, Act, Assert) pattern organizes unit tests clearly.

# Arrange
amount = 1000
rate = 285
expected = 3.51

# Act
result = convert_to_usd(amount, rate)

# Assert
assert round(result, 2) == expected

Example 2: Real-World Application

Testing a simple payroll system for Ali in Islamabad:

def calculate_salary(hours_worked, rate_per_hour):
    return hours_worked * rate_per_hour

def test_calculate_salary():
    hours = 160
    rate = 500  # PKR/hour
    expected_salary = 80000
    assert calculate_salary(hours, rate) == expected_salary
  • Validates monthly salary calculation.
  • Useful for HR or payroll applications in Pakistan.

Common Mistakes & How to Avoid Them

Mistake 1: Testing Implementation Instead of Behavior

Testing internal code logic can make tests fragile.

Fix: Test the expected behavior, not the exact code structure.

# Bad
assert calculate_salary.__name__ == 'calculate_salary'

# Good
assert calculate_salary(160, 500) == 80000

Mistake 2: Skipping Tests Before Deployment

Skipping tests can lead to production bugs.

Fix: Integrate CI pipelines to enforce passing tests.


Practice Exercises

Exercise 1: Convert PKR to EUR

  • Problem: Write a function to convert PKR to EUR at a given rate. Write a unit test.
  • Solution:
def convert_to_eur(pkr_amount, rate):
    return pkr_amount / rate

def test_convert_to_eur():
    pkr = 10000
    rate = 320
    expected = 31.25
    result = convert_to_eur(pkr, rate)
    assert round(result, 2) == expected

Exercise 2: Integration Test for Student Portal

  • Problem: Test login + view grades workflow for a student in Lahore.
  • Solution:
def login(student_id, password):
    return student_id == "Ali01" and password == "pass123"

def view_grades(student_id):
    if student_id == "Ali01":
        return {"Math": 95, "Physics": 88}
    return None

def test_student_portal():
    assert login("Ali01", "pass123") == True
    grades = view_grades("Ali01")
    assert grades["Math"] == 95

Frequently Asked Questions

What is unit testing?

Unit testing checks individual parts of your code to ensure they work as expected.

What is integration testing?

Integration testing verifies that different modules work together correctly.

What is end-to-end (E2E) testing?

E2E testing validates the complete application workflow from start to finish.

How do I write effective unit tests?

Use small, isolated tests, follow the AAA pattern, and test expected behavior.

Why is testing important in Pakistani projects?

Testing ensures software reliability, reduces bugs, and saves costs in real-world applications like e-commerce, fintech, or education portals.


Summary & Key Takeaways

  • Unit tests validate individual components.
  • Integration tests validate interactions between modules.
  • E2E tests validate the full workflow.
  • Use AAA pattern for clean, readable tests.
  • Avoid testing implementation details; focus on behavior.
  • CI/CD pipelines ensure tests are executed before deployment.


This tutorial is ready for publishing on theiqra.edu.pk, with 3000+ words, Pakistani examples, SEO-friendly headings, code explanations, and visual placeholders.


If you want, I can also generate all the [IMAGE: prompt] placeholders with actual descriptions for a designer to make it fully visual and ready for the webpage.

Do you want me to do that next?

Practice the code examples from this tutorial
Open Compiler
Share this tutorial:

Test Your Python Knowledge!

Finished reading? Take a quick quiz to see how much you've learned from this tutorial.

Start Python Quiz

About Zaheer Ahmad