The framework to go with is unit testing. Unit testing is the individual testing of each function or method alone. The purpose is to validate each unit of the library and that the software code performs as excepted . We use PyTest , Example:

This is the class that we want to test:

class Calculator:
    def add(self, a, b):
        return a + b

    def subtract(self, a, b):
        return a - b

    def multiply(self, a, b):
        return a * b

    def divide(self, a, b):
        if b == 0:
            raise ValueError("Cannot divide by zero!")
        return a / b

Using the PyTest library one can write the following :

import pytest
from calc import Calculator

calc = Calculator()

def test_add():
    assert calc.add(10, 5) == 15

def test_subtract():
    assert calc.subtract(10, 5) == 5

def test_multiply():
    assert calc.multiply(10, 5) == 50

def test_divide():
    assert calc.divide(10, 5) == 2

def test_divide_by_zero():
    with pytest.raises(ValueError):
        calc.divide(10, 0)

Running the command pytest will result in the following report  (as said running pytest runs all the tests not just in a specific python file but in the full director) also you can specify the file using this  pytest path/to/test_file.py )

================================================= test session starts =================================================
platform win32 -- Python 3.13.3, pytest-8.3.5, pluggy-1.5.0
rootdir: C:\\Users\\LEGION\\Desktop\\calculator
collected 5 items

test_calculator_pytest.py .....                                                                                  [100%]

================================================== 5 passed in 0.03s ==================================================

Now what if we want to test different edge cases, we use parametrization for automating things like this

import pytest
from calc import Calculator

calc = Calculator()

@pytest.mark.parametrize("a, b, expected", [
    (1, 2, 3),
    (10, 5, 15),
    (-1, -1, -2)
])
def test_add_parametrized(a, b, expected):
    assert calc.add(a, b) == expected

Leveraging thing up more, we can define fixtures (a function that provides a fixed baseline environment for tests) using the @fixture decorator

import pytest
from calc import Calculator

@pytest.fixture
def calc():
    return Calculator()

def test_add(calc):
    assert calc.add(2, 3) == 5

def test_subtract(calc):
    assert calc.subtract(7, 4) == 3

And both can be combined to generate a python file the tests the whole class on different testcase units

import pytest
from calc import Calculator

@pytest.fixture
def calc():
    return Calculator()

@pytest.mark.parametrize("a, b, expected", [
    (1, 2, 3),
    (10, 5, 15),
    (-1, -1, -2),
    (0, 0, 0)
])
def test_add(calc, a, b, expected):
    assert calc.add(a, b) == expected

@pytest.mark.parametrize("a, b, expected", [
    (5, 2, 3),
    (10, 10, 0),
    (0, 5, -5)
])
def test_subtract(calc, a, b, expected):
    assert calc.subtract(a, b) == expected