Data AnalyticsPython foundations for analysts

Test a business calculation with normal and boundary cases

PK
Pankit Kumar
Sr. Data Scientist at Parexel (a Goldman Sachs–backed company) · 20 September 2026 · 3 min read
Technically reviewed by Ishaan Sharma
In this article (6 sections)

Derive tests from the calculation's meaning, not from the lines of code it happens to use. A monthly paid-order report needs evidence about period boundaries, payment status, identity and empty results. A test that merely repeats the implementation can preserve the same mistake twice.

Begin with a tiny dataset whose correct answer can be calculated independently. Then add cases that would distinguish the intended rule from a plausible wrong rule.

Write the contract before the assertion

The Python reporting lab defines paid_summary over validated unique orders. It includes Paid orders from the first day of the selected month up to, but excluding, the next month's first day. Customer count means distinct customer IDs among those selected orders.

Parsing and duplicate validation belong to the loader. Testing the summary does not establish that raw CSV input is valid; those are separate boundaries.

Use a fixture that catches several plausible errors

python
from datetime import date
from decimal import Decimal
from report import Order, paid_summary

orders = [
    Order("A", "0012", date(2025, 12, 31), Decimal("100.00"), "Paid"),
    Order("B", "0012", date(2026, 1, 1), Decimal("19.00"), "Paid"),
    Order("C", "0012", date(2026, 1, 31), Decimal("5.00"), "Paid"),
    Order("D", "0042", date(2026, 1, 31), Decimal("8.00"), "Pending"),
    Order("E", "0042", date(2026, 2, 1), Decimal("10.00"), "Paid"),
]
january = paid_summary(orders, "2026-01")
assert january["paid_orders"] == 2
assert january["known_customers"] == 1
assert january["paid_amount_inr"] == "24.00"
empty = paid_summary(orders, "2026-03")
assert (empty["paid_orders"], empty["known_customers"], empty["paid_amount_inr"]) == (0, 0, "0.00")
assert paid_summary(list(reversed(orders)), "2026-01") == january
print("Period, status, identity, empty result and order independence verified")

The prior-year record catches a missing lower boundary. The February record catches an inclusive upper boundary. The pending order catches a missing status filter. Two January orders from one customer distinguish order count from customer count.

The reversal check expresses an invariant: changing input order should not change this aggregate. It is useful because it tests a property beyond one hard-coded total.

Test failure behavior separately

The lab's 15-test suite covers invalid amounts, invalid dates, missing customer IDs, identical replays, conflicting keys, schema errors, malformed CSV quoting and source/output collisions. It also runs the CLI to verify the partial-result exit status.

Run python verify.py from the lab directory to regenerate its verification record. Python's unittest reference explains test cases and assertions; the value of this suite comes from its business cases, not the test framework name.

An expected exception should be specific enough to identify the intended failure. Accepting any exception can let a misspelled variable pass a test that was supposed to validate a rejected date.

Prove that a test can detect a mistake

Temporarily consider changing the upper comparison from less-than to less-than-or-equal. The February 1 record would enter January and break the expected total. That is a useful test because it distinguishes two realistic implementations.

Similarly, replacing distinct customer IDs with selected-row count would change January's customer count from one to two. A fixture containing only one order per customer would fail to expose that defect.

You do not need to keep intentionally broken production code. Use the reasoning to improve fixture design, or perform controlled mutation checks in a disposable copy.

Avoid approval by test count

Fifteen meaningful tests can still miss an unmodeled requirement. A hundred assertions against the same happy path can miss a critical boundary. Review coverage against the contract and known risks, not only a green percentage.

The summary function assumes its Order objects were already validated and deduplicated. If a new caller bypasses the loader, that assumption must remain visible or the function's contract must be expanded.

Exercise: add a zero-value Paid order. Decide whether it should count as an order and customer under the stated metric, then write expected values before changing the implementation.

NeuraPath's Data Analytics with Generative AI course connects Python testing with business definitions. A strong analytical test explains which wrong conclusion it prevents.

Continue learning

This article is part of the Python foundations for analysts sequence. Use the neighbouring tasks when you need the prerequisite or the next application.

PK
Pankit Kumar
Lead Instructor, NeuraPath Academy

Pankit Kumar has 10 years in Data Science & AI, building and shipping production systems in regulated pharma and clinical environments. He is a freelance trainer at Boston Institute of Analytics, AnalytixLabs and Scaler, and has taught this material to thousands of working professionals.

This article is part of our Data Analytics with Generative AI programme — 3–4 months. The full analyst stack — Excel, SQL, Power BI and Python pipelines — then a generative-AI layer you can prove is right.

Explore Data Analytics with Generative AI
Counselling is free · no obligation

Not sure which programme fits?

Tell us your background and we will map it to the right entry point — including saying so when a cheaper programme is the better fit. A counsellor replies within one working day.