Extensions to the Python standard library unit testing framework
Sophisticated assertion system with 46 matchers for complex comparisons and validations. Matchers provide a composable, expressive way to specify test expectations beyond simple equality checks.
Base classes and exceptions for the matcher system.
class Matcher:
"""
Abstract base class for all matchers.
Defines the protocol that all matchers must implement
for composable assertion logic.
"""
def match(self, other):
"""
Try to match other with this matcher.
Args:
other: Object to match against
Returns:
None if match succeeds, Mismatch object if it fails
"""
def describe(self):
"""
Describe what this matcher matches.
Returns:
str: Human-readable description
"""
class Mismatch:
"""
Represents a matcher mismatch with detailed description.
"""
def __init__(self, description):
"""
Create a mismatch.
Args:
description (str): Description of the mismatch
"""
def describe(self):
"""
Get the mismatch description.
Returns:
str: Detailed mismatch information
"""
class MismatchError(Exception):
"""
Exception raised when matcher assertion fails.
"""Fundamental matchers for comparing values, strings, and basic data types.
def Equals(expected):
"""
Match if objects are equal using == operator.
Args:
expected: Expected value
Returns:
Matcher: Equality matcher
"""
def NotEquals(expected):
"""
Match if objects are not equal using != operator.
Args:
expected: Value that should not match
Returns:
Matcher: Inequality matcher
"""
def Is(expected):
"""
Match using identity comparison (is operator).
Args:
expected: Expected object identity
Returns:
Matcher: Identity matcher
"""
def IsInstance(class_or_tuple):
"""
Match if object is instance of specified type(s).
Args:
class_or_tuple: Class or tuple of classes
Returns:
Matcher: Instance type matcher
"""
def Contains(contained):
"""
Match if object contains specified item.
Args:
contained: Item that should be contained
Returns:
Matcher: Containment matcher
"""
def StartsWith(expected):
"""
Match if string starts with specified substring.
Args:
expected (str): Expected prefix
Returns:
Matcher: String prefix matcher
"""
def EndsWith(expected):
"""
Match if string ends with specified substring.
Args:
expected (str): Expected suffix
Returns:
Matcher: String suffix matcher
"""
def MatchesRegex(pattern, flags=0):
"""
Match string against regular expression pattern.
Args:
pattern (str): Regular expression pattern
flags (int): Regex flags (re.IGNORECASE, etc.)
Returns:
Matcher: Regular expression matcher
"""
def GreaterThan(expected):
"""
Match if value is greater than expected value.
Args:
expected: Value to compare against
Returns:
Matcher: Greater than comparison matcher
"""
def LessThan(expected):
"""
Match if value is less than expected value.
Args:
expected: Value to compare against
Returns:
Matcher: Less than comparison matcher
"""
def HasLength(expected):
"""
Match if object has expected length.
Args:
expected (int): Expected length
Returns:
Matcher: Length matcher
"""
def SameMembers(expected):
"""
Match if iterables have same members regardless of order.
Args:
expected: Iterable with expected members
Returns:
Matcher: Set membership matcher
"""Matchers for complex data structures like lists, dictionaries, and objects.
def MatchesDict(d):
"""
Match dictionary structure with value matchers.
Args:
d (dict): Dictionary mapping keys to matchers
Returns:
Matcher: Dictionary structure matcher
"""
def ContainsDict(d):
"""
Match if dictionary contains expected key-value pairs.
Args:
d (dict): Expected key-value pairs
Returns:
Matcher: Dictionary containment matcher
"""
def ContainedByDict(d):
"""
Match if dictionary is contained within another dictionary.
Args:
d (dict): Container dictionary
Returns:
Matcher: Dictionary containment checker
"""
def KeysEqual(expected):
"""
Match if dictionary keys equal expected set of keys.
Args:
expected: Expected keys (iterable)
Returns:
Matcher: Dictionary keys matcher
"""
def MatchesListwise(matchers):
"""
Match lists element by element with corresponding matchers.
Args:
matchers (list): List of matchers for each element
Returns:
Matcher: Element-wise list matcher
"""
def MatchesSetwise(matchers):
"""
Match sets ignoring order with corresponding matchers.
Args:
matchers: Iterable of matchers
Returns:
Matcher: Unordered set matcher
"""
def MatchesStructure(**kwargs):
"""
Match object attributes against specified matchers.
Args:
**kwargs: Attribute names mapped to matchers
Returns:
Matcher: Object structure matcher
"""
def ContainsAll(items):
"""
Match if object contains all specified items.
Args:
items: Iterable of items that should be contained
Returns:
Matcher: Multiple containment matcher
"""Matchers for testing exception behavior and error conditions.
def Raises(exception_matcher):
"""
Match if callable raises expected exception.
Args:
exception_matcher: Matcher for the expected exception
Returns:
Matcher: Exception raising matcher
"""
def MatchesException(exception, value_re=None):
"""
Match exception instances or types with optional attribute matching.
Args:
exception: Exception class or instance to match
value_re (str): Optional regex for exception message
Returns:
Matcher: Exception matcher
"""
def raises(exception_matcher):
"""
Context manager version of Raises matcher.
Args:
exception_matcher: Matcher for expected exception
Returns:
Context manager for exception testing
"""Matchers for filesystem operations and file content verification.
def PathExists():
"""
Match if filesystem path exists.
Returns:
Matcher: Path existence matcher
"""
def FileExists():
"""
Match if path exists and is a regular file.
Returns:
Matcher: File existence matcher
"""
def DirExists():
"""
Match if path exists and is a directory.
Returns:
Matcher: Directory existence matcher
"""
def FileContains(matcher):
"""
Match file contents against expected content.
Args:
matcher: Matcher for file contents
Returns:
Matcher: File content matcher
"""
def DirContains(filenames):
"""
Match if directory contains specified files.
Args:
filenames: Expected filenames (iterable)
Returns:
Matcher: Directory content matcher
"""
def HasPermissions(expected):
"""
Match file permissions against expected permissions.
Args:
expected: Expected permission bits
Returns:
Matcher: File permissions matcher
"""
def SamePath(expected):
"""
Match if paths refer to the same filesystem location.
Args:
expected: Expected path
Returns:
Matcher: Path equivalence matcher
"""
def TarballContains(filenames):
"""
Match contents of tarball archives.
Args:
filenames: Expected filenames in tarball
Returns:
Matcher: Tarball content matcher
"""Matcher combinators for building complex matching logic.
def MatchesAll(*matchers):
"""
Match against multiple matchers (logical AND).
Args:
*matchers: Matchers that must all succeed
Returns:
Matcher: Conjunction matcher
"""
def MatchesAny(*matchers):
"""
Match against any of multiple matchers (logical OR).
Args:
*matchers: Matchers, at least one must succeed
Returns:
Matcher: Disjunction matcher
"""
def Not(matcher):
"""
Negate/invert the result of another matcher.
Args:
matcher: Matcher to negate
Returns:
Matcher: Negated matcher
"""
def AllMatch(matcher):
"""
Match if all items in iterable match the given matcher.
Args:
matcher: Matcher to apply to each item
Returns:
Matcher: Universal quantification matcher
"""
def AnyMatch(matcher):
"""
Match if any item in iterable matches the given matcher.
Args:
matcher: Matcher to apply to items
Returns:
Matcher: Existential quantification matcher
"""
def AfterPreprocessing(preprocessor, matcher):
"""
Apply preprocessing function before matching.
Args:
preprocessor: Function to transform input
matcher: Matcher to apply to transformed data
Returns:
Matcher: Preprocessing matcher
"""
def Annotate(annotation, matcher):
"""
Add annotation/description to existing matcher.
Args:
annotation (str): Additional description
matcher: Matcher to annotate
Returns:
Matcher: Annotated matcher
"""
def MatchesPredicate(predicate, message=None):
"""
Match using predicate function.
Args:
predicate: Function returning bool
message (str): Optional description
Returns:
Matcher: Predicate-based matcher
"""
def MatchesPredicateWithParams(predicate, message=None, **params):
"""
Match using predicate function with additional parameters.
Args:
predicate: Function accepting value and params
message (str): Optional description
**params: Additional parameters for predicate
Returns:
Matcher: Parameterized predicate matcher
"""Matchers with fixed behavior for testing and composition.
def Always():
"""
Matcher that always succeeds (never fails).
Returns:
Matcher: Always-succeeding matcher
"""
def Never():
"""
Matcher that never succeeds (always fails).
Returns:
Matcher: Always-failing matcher
"""Matcher for integrating with Python's doctest module.
def DocTestMatches(expected, flags=0):
"""
Match string against doctest expected output format.
Args:
expected (str): Expected doctest output
flags (int): Doctest option flags
Returns:
Matcher: DocTest output matcher
"""Matchers for testing warning emissions and deprecation behavior.
def Warnings(matchers):
"""
Match warnings emitted during code execution.
Args:
matchers: Matchers for expected warnings
Returns:
Matcher: Warning emission matcher
"""
def WarningMessage(category=None, message=None, filename=None, lineno=None):
"""
Match specific warning message details.
Args:
category: Warning category class
message: Warning message matcher
filename: Source filename matcher
lineno: Line number matcher
Returns:
Matcher: Warning message matcher
"""
def IsDeprecated():
"""
Match deprecated functionality warnings.
Returns:
Matcher: Deprecation warning matcher
"""import testtools
from testtools.matchers import *
class TestMatchers(testtools.TestCase):
def test_basic_matchers(self):
# String matchers
self.assertThat("Hello World", Contains("World"))
self.assertThat("test.py", EndsWith(".py"))
self.assertThat("function_name", MatchesRegex(r'\w+_\w+'))
# Numeric matchers
self.assertThat(42, GreaterThan(40))
self.assertThat([1, 2, 3], HasLength(3))
# Type matchers
self.assertThat([], IsInstance(list))
self.assertThat("test", Not(IsInstance(int)))def test_complex_structures(self):
data = {
'users': [
{'name': 'Alice', 'age': 30},
{'name': 'Bob', 'age': 25}
],
'status': 'active',
'count': 2
}
# Match dictionary structure
self.assertThat(data, MatchesDict({
'users': HasLength(2),
'status': Equals('active'),
'count': GreaterThan(0)
}))
# Match list elements
self.assertThat(data['users'], MatchesListwise([
MatchesDict({'name': StartsWith('A'), 'age': GreaterThan(25)}),
MatchesDict({'name': StartsWith('B'), 'age': LessThan(30)})
]))def test_exceptions(self):
# Test specific exception
self.assertThat(
lambda: int('not_a_number'),
Raises(MatchesException(ValueError))
)
# Test exception message
with raises(MatchesException(ValueError, "invalid literal.*")):
int('not_a_number')def test_filesystem(self):
# Test file operations
self.assertThat('/etc/passwd', FileExists())
self.assertThat('/tmp', DirExists())
self.assertThat('config.txt', FileContains(Contains('version')))def test_matcher_combinations(self):
# Logical combinations
self.assertThat(42, MatchesAll(
GreaterThan(40),
LessThan(50),
IsInstance(int)
))
# Check all list items
numbers = [2, 4, 6, 8]
self.assertThat(numbers, AllMatch(
MatchesAll(IsInstance(int), lambda x: x % 2 == 0)
))
# Preprocessing
self.assertThat(" trimmed ", AfterPreprocessing(
str.strip,
Equals("trimmed")
))Install with Tessl CLI
npx tessl i tessl/pypi-testtools