DEV Community

Tester Academy
Tester Academy

Posted on

Write Your First Python Unit Tests with pytest: A Discount Calculator Example

A discount calculator is a useful starting point for learning unit testing. Its rules are simple, but it still gives you normal inputs, boundary values and errors to check.

Let’s build one in Python and test it with pytest.

Decide What the Function Should Do

Before writing tests, define the expected behaviour.
Understanding the basics of unit testing helps you turn these requirements into focused checks.

Our function should:

  • Apply a percentage discount to a price.
  • Accept discounts from 0% to 100%.
  • Reject discounts outside that range.

For a ₹1,000 product, a 10% discount should return ₹900. A zero discount should leave the price unchanged.

This example assumes a valid, non-negative numeric price. Production pricing also needs input validation and explicit currency-rounding rules.

Create the Discount Function

Create a folder for the example. Inside it, save this code as discount.py:

def discounted_price(price, discount): if not 0 <= discount <= 100: raise ValueError("Discount must be between 0 and 100") return price * (100 - discount) / 100

The condition rejects invalid percentages. The final line calculates the amount remaining after the discount.

Install pytest

With Python installed, open a terminal in your project folder and run:
python -m pip install pytest
Next, create a file named test_discount.py alongside discount.py.
The test_ prefix lets pytest discover the test file using its default naming rules.

Write Your First Test

Add this code to test_discount.py:
from discount import discounted_pricedef test_ten_percent_discount(): price = 1000 result = discounted_price(price, 10) assert result == 900

This follows Arrange, Act, Assert:

  • Arrange: Prepare the original price.
  • Act: Call the discount function.
  • Assert: Check that the result equals ₹900.
  • Run it with:
  • python -m pytest -q
  • If everything is correct, the summary should show 1 passed.

Test the Boundary Values

A normal discount is only one case. Add separate tests for the lowest and highest accepted percentages:

def test_zero_discount(): assert discounted_price(1000, 0) == 1000def test_full_discount(): assert discounted_price(1000, 100) == 0
These tests check that valid boundary values remain accepted. Each test has a descriptive name, making failures easier to identify.

Check Invalid Discounts

Add import pytest at the top of test_discount.py, then include:

def test_negative_discount():    with pytest.raises(ValueError):        discounted_price(1000, -10)def test_discount_above_limit():    with pytest.raises(ValueError):        discounted_price(1000, 120)
Enter fullscreen mode Exit fullscreen mode

pytest.raises checks whether the function raises the expected exception.
These tests pass when invalid discounts trigger ValueError. They fail if the function silently accepts those values.

Run the command again:

python -m pytest -q
The expected summary is now 5 passed.

See What a Failure Looks Like

Temporarily change the calculation in discount.py to:
return price * discount / 100
Run the tests again. The 10% test fails because the function returns ₹100, the discount amount, instead of ₹900, the final price.

The failure identifies a mismatch between the expected and actual result. Check the requirement and implementation, then restore the correct formula.

Final Thoughts
You now have five tests covering a standard discount, two boundaries and two invalid inputs.

They check the calculation’s defined behaviour. They do not verify checkout, payments or order creation.

As a next exercise, define what should happen when the original price is negative. Write a test for that requirement, then update the function to satisfy it.

Top comments (0)