Readable failures save debugging time, and most teams eventually run unittest code with pytest.
Failure output is configurable per TestCase:
maxDiffcaps the length of diffs shown byassertEqualon long sequences or strings (default 640 characters). SetmaxDiff = Nonein a class to always see the full diff.longMessage(default True) appends yourmsg=to the standard message instead of replacing it.addTypeEqualityFunc(MyType, func)registers a comparison function used byassertEqualwhen both arguments have exactly that type, so domain objects get domain-specific failure messages. The function should raiseself.failureException(msg)on mismatch.- Custom assertion helpers: write methods that call the standard ones, and set
__unittest = Trueat module level in a helper module to hide its frames from tracebacks (an undocumented but long-standing convention).
pytest interop: pytest collects TestCase subclasses natively, running setUp, cleanups, skip decorators and subTest. You can adopt pytest features gradually: plain assert with rich introspection, fixtures for new tests, plugins such as coverage and xdist. Some pytest features (fixtures injected as arguments, parametrize) don't work on TestCase methods, so new tests are usually written as plain functions.
Example
import unittest
from dataclasses import dataclass
@dataclass
class Money:
amount: int
currency: str
class TestMoney(unittest.TestCase):
maxDiff = None
def setUp(self):
self.addTypeEqualityFunc(Money, self.assertMoneyEqual)
def assertMoneyEqual(self, a, b, msg=None):
if a.currency != b.currency:
raise self.failureException(f"currency {a.currency} != {b.currency}")
if a.amount != b.amount:
raise self.failureException(f"{a.currency} amounts differ by {a.amount - b.amount}")
def test_total(self):
self.assertEqual(Money(1050, "EUR"), Money(1000, "EUR"))
unittest.main(exit=False)
# AssertionError: EUR amounts differ by 50Remember
- maxDiff = None shows full diffs; longMessage appends msg=
- addTypeEqualityFunc gives assertEqual domain-specific messages
- pytest runs TestCase classes unchanged, enabling gradual migration
Watch out for
- Truncated diffs ('Diff is 1200 characters long') hiding the real difference; set maxDiff = None while debugging.