tms: Test Match Special

tms lets you test values in test code, where you may not be able to test against an exact, known value.

Some quick examples:

Test an object's class and instance attributes:

assert zoo.get('elephant') == tms.InstanceOf(Elephant, name='nelly')

Match data structures:

assert resultset.any() == {'id': tms.InstanceOf(int),
                           'name': tms.Contains('bob'),
                           'data': tms.Anything()}

Common types have shortcuts, eg:


Test for in / not in:

assert 'business' == tms.Contains('sin')
assert 'my lunch' == tms.DoesntContain('nuts')

Test attributes:

assert Circle(1) == tms.InstanceOf(Circle, radius=1)

assert Circle(1) == tms.InstanceOf(Circle, radius=tms.InstanceOf(int))

assert Circle(1) == tms.InstanceOf(Circle, has_attrs=['radius'])

Test for arbitrary conditions:

assert 1 == tms.Int(lambda x: x > 0)
assert Circle(1) == tms.InstanceOf(Circle, lambda x: x.radius == 1)

Test dictionaries or dict-like objects:

# Check that it contains keys and values
assert {'x': 1} == tms.DictLike(x=1)

# Check that it contains certain keys
assert dict(x=1, y=2) == tms.Contains('x', 'y')

# Check that it doesn't contain certain keys
assert dict(x=1, y=2) == tms.DoesntContain('foo', 'bar')

Combining tests:

assert mylunch == tms.InstanceOf(Sandwich) & tms.DoesntContain(cheese)

Unlike hamcrest, tms uses the __eq__ method to evaluate comparisons. This means it works with python's built in assert statement. This also means it works well with other test libraries: you can drop a tms.Matcher object into any regular equality test and have it work.

Note that this also means that it may not work for objects that override the __eq__ method. If the matcher doesn't seem to be firing, try putting it on the left hand side of the comparison:

>>> import tms
>>> class MySpecialObject(object):
...     def __eq__(self, other):
...         return False
>>> MySpecialObject() == tms.Anything()
>>> tms.Anything() == MySpecialObject()