Python unittest runs assertions inside test cases and reports failures separately from uncaught test errors.
Python unittest: test rejected input and preserve state after failure
Operation contract
The receipt-total boundary requires a nonnegative exact integer quantity and a nonnegative exact integer price. Three tests check an ordinary total, the accepted zero-quantity boundary and rejection of bool. An in-memory runner suppresses variable timing text while the program prints the stable pass/fail result and executed test count. Tests use the standard library without a dependency install.
Failure and ownership boundary
An accepted example cannot prove all inputs work. Choose tests for the failure contract and any state that must survive it. Catching every exception in a test can hide the wrong failure type; assertRaises states the exception the boundary promises. Python inventory project: validate a batch before replacing stored state needs a before/after snapshot assertion when a later change fails. A successful unit suite is not a deployment or database-isolation test.
Working program
import io
import unittest
def receipt_total(quantity, unit_minor):
if type(quantity) is not int or type(unit_minor) is not int:
raise TypeError("integer fields required")
if quantity < 0 or unit_minor < 0:
raise ValueError("negative field")
return quantity * unit_minor
class ReceiptTotalChecks(unittest.TestCase):
def test_total(self):
self.assertEqual(receipt_total(3, 125), 375)
def test_zero_quantity(self):
self.assertEqual(receipt_total(0, 125), 0)
def test_boolean_rejected(self):
with self.assertRaises(TypeError):
receipt_total(True, 125)
suite = unittest.defaultTestLoader.loadTestsFromTestCase(ReceiptTotalChecks)
result = unittest.TextTestRunner(stream=io.StringIO()).run(suite)
print("passed:", result.wasSuccessful())
print("tests:", result.testsRun)Output
passed: True
tests: 3Costs and limits
The three fixtures perform bounded arithmetic and allocate one local result stream. Production data and concurrency schedules require their own tests; increasing the test count alone does not improve that coverage.
Common Mistakes
- Check the promised exception type instead of swallowing every error.
- Include state-preservation assertions for failed batches.
Connected lessons
Python functions: define units, validate input and return a result, Python inventory project: validate a batch before replacing stored state, Python collection exercise: reject repeated receipt IDs before committing state.
Related Python operation checks
Pytest fixtures: isolated files and parameterized rejection tests, Python unittest.mock: inject a collaborator failure before publication.
Follow the related contract
Hypothesis property tests: compare generated cases with an independent contract, Coverage.py branch coverage: execution paths are not correctness assertions.
Check the next state boundary
Python refactoring: preserve rejected inputs as well as accepted results, Python mutation testing: prove a suite rejects selected wrong implementations.
Trace the related workflow
Python unittest subTest: label several cases without aborting the method.
