PythiloLesson 5 of 12 · progress kept in this browser

Testing exceptions in detail

pytest.raises(ValueError) passes for any ValueError, including one raised by a bug on a different line. Two more tools make a test say which error it means.

import pytest

class OutOfStock(Exception):
    def __init__(self, item, short):
        self.short = short
        super().__init__(f"{item} short")

def take(stock, item, n):
    if stock[item] < n:
        short = n - stock[item]
        raise OutOfStock(item, short)
    stock[item] -= n

stock = {"tea": 2}
with pytest.raises(OutOfStock,
                   match="tea") as info:
    take(stock, "tea", 5)
print(info.value.short, stock)
  • match is a regular expression, searched for in the message. Wrap literal text in re.escape if it has special characters.
  • as info keeps the exception. After the block, info.value is the exception object, with its attributes.
Your task

withdraw and InsufficientFunds are written for you. Write test_rejects_zero_amount, using match to check it is the ValueError about a positive amount, and test_insufficient_funds, which withdraws 50 from {"ann": 30} and checks that the exception's needed is 20 and the balance is still 30.

The first run loads pytest into this browser.