Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Python unittest: test rejected input and preserve state after failure

Last updated: 30 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

Python unittest runs assertions inside test cases and reports failures separately from uncaught test errors.

Download Python source kit

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

python
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

Output
passed: True
tests: 3

Costs 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.

python
unittest-contracts
Storage details