backend / python core / 14_testing.md

Software Testing Overview

4 min read source

Software Testing Overview

Software testing is a critical aspect of the software development lifecycle that ensures applications function correctly, meet requirements, and provide a seamless user experience. This overview covers common types of tests and explores the differences between two popular Python testing frameworks: unittest and pytest.

Common Types of Tests

Understanding the various types of software tests is essential for implementing effective testing strategies. Here are the most common types:

1. Unit Testing

  • Definition: Testing individual components or units of code, such as functions or classes, in isolation.
  • Purpose: To verify that each unit performs as intended.
  • Tools: unittest, pytest (Python); JUnit (Java).

2. Integration Testing

  • Definition: Testing the interactions between different units or modules.
  • Purpose: To identify issues in the interfaces and interactions between integrated components.
  • Tools: Postman, Selenium.

3. System Testing

  • Definition: Testing the complete and integrated software system.
  • Purpose: To validate the system’s compliance with the specified requirements.
  • Tools: Selenium, QTP.

4. Acceptance Testing

  • Definition: Testing conducted to determine whether the system meets the business requirements and is ready for delivery.
  • Purpose: To gain acceptance from the end-users or stakeholders.
  • Types: User Acceptance Testing (UAT), Operational Acceptance Testing (OAT).

5. Regression Testing

  • Definition: Re-testing the software after changes have been made to ensure that existing functionalities are not broken.
  • Purpose: To detect unintended side effects of code changes.
  • Tools: Selenium, QTP.

6. Performance Testing

  • Definition: Assessing the speed, responsiveness, and stability of a software application under a particular workload.
  • Purpose: To ensure the software performs well under expected and peak conditions.
  • Types: Load Testing, Stress Testing, Endurance Testing.

7. Security Testing

  • Definition: Identifying vulnerabilities and ensuring that the software protects data and maintains functionality as intended.
  • Purpose: To protect against malicious attacks and ensure data integrity and confidentiality.
  • Tools: OWASP ZAP, Burp Suite.

Difference Between unittest and pytest

Both unittest and pytest are popular testing frameworks in Python, each with its unique features and advantages. Understanding their differences can help you choose the right tool for your project.

unittest

  • Overview:

    • unittest is a built-in Python testing framework inspired by Java’s JUnit.
    • Part of the Python standard library, requiring no additional installation.
  • Features:

    • Test Cases: Organized into test classes by subclassing unittest.TestCase.
    • Assertions: Provides a comprehensive set of assertion methods (e.g., assertEqual, assertTrue).
    • Setup and Teardown: Methods like setUp() and tearDown() for preparing and cleaning up before and after tests.
    • Test Discovery: Can automatically discover tests in modules and packages.
  • Pros:

    • No external dependencies since it’s part of the standard library.
    • Familiar to developers with experience in xUnit frameworks.
    • Well-suited for simple testing scenarios.
  • Cons:

    • Verbose syntax can lead to more boilerplate code.
    • Less flexible and fewer features compared to pytest.
    • Limited support for advanced testing techniques.

pytest

  • Overview:

    • pytest is a third-party testing framework known for its simplicity and scalability.
    • Requires installation via pip (pip install pytest).
  • Features:

    • Simple Syntax: Tests are written as simple functions without the need for classes.
    • Powerful Fixtures: Advanced fixture system for setup and teardown, promoting reusability and modularity.
    • Rich Assertions: Enhanced assertion introspection, providing detailed information on test failures.
    • Plugins: Extensive plugin ecosystem for extended functionality (e.g., pytest-cov for coverage, pytest-xdist for parallel execution).
    • Parameterization: Easily run tests with different inputs using @pytest.mark.parametrize.
  • Pros:

    • Concise and readable test code reduces boilerplate.
    • Highly extensible with a wide range of plugins.
    • Superior assertion reporting aids in debugging.
    • Flexible fixture management accommodates complex testing scenarios.
    • Better support for complex testing workflows.
  • Cons:

    • Requires installation of a third-party package.
    • May have a steeper learning curve for those accustomed to unittest.
    • Potential compatibility issues with legacy codebases using unittest.

Example Comparison

unittest Example

import unittest

class TestMathOperations(unittest.TestCase):
    def setUp(self):
        self.a = 10
        self.b = 5

    def test_addition(self):
        self.assertEqual(self.a + self.b, 15)

    def test_subtraction(self):
        self.assertEqual(self.a - self.b, 5)

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

---

## Interview angle

- **"What does the test pyramid say?"** - many fast unit tests, fewer integration tests, very few end-to-end. Inverting it gives a slow, flaky suite nobody runs, which is worse than fewer tests.
- **"What makes a good unit test?"** - one behaviour, deterministic, fast, and named so a failure tells you what broke without reading the body. Tests asserting implementation detail rather than behaviour break on every refactor.
- **"Is 100% coverage the goal?"** - no. Coverage shows what was executed, not what was verified; a test with no assertions still covers lines. Use it to find untested areas, not as a target.