Skip to content

Instantly share code, notes, and snippets.

@offbyone
Created April 13, 2015 18:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save offbyone/79f8597d763054bf4492 to your computer and use it in GitHub Desktop.
Save offbyone/79f8597d763054bf4492 to your computer and use it in GitHub Desktop.
"""Goals:
1. Easy matcher definitions from methods, without the class plumbing.
>>> from hamcrest.decorators import matcher
>>> @matcher()
... def checks_out(item):
... return item.checks_out()
...
>>> assert_that(value, checks_out())
2. Easy adapting of existing methods to matchers
>>> import my_lib
>>> from hamcrest.decorators import matcher
>>> checks_out = matcher()(my_lib.checks_out)
>>> assert_that(value, checks_out())
3. transparent adaptive wrapping of boolean/assertion methods in
assertions
>>> import my_lib
>>> assert_that(value, my_lib.checks_out())
4. Flexible customization of matchers:
>>> import my_lib # has a checks_out_this(thing, item) -- item will be used as the hamcrest arg, thing must be provided.
>>> from hamcrest.decorators import matcher
>>> checks_out_this = matcher()(my_lib.checks_out_this)
>>> assert_that(value, checks_out_this(thing))
5. Descriptions should be simple -- first line of the docstring becomes describe_to
6. describe_mismatch can be added via a new decorator or via assert in the method.
7. Matcher methods with multiple arguments should be curried by the decorator
>>> @matcher(versus=3)
... def this_vs_that(versus, item):
... pass
8. Matcher methods can allow selecting a different value argument if needed
>>> @matcher(_value_arg="value", versus=3)
... def this_vs_that(versus, value):
... pass
... should one detect this on decoration?
"""
"""An example of a method-based matcher that does not provide its own
describe_mismatch support.
A method decorated with @matcher can be used in any role that a
matcher would fit.
"""
from hamcrest.decorators import matcher
@matcher()
def greater_than_three(value):
return value > 3
assert_that(4, greater_than_three())
"""if the matcher doesn't take customizations, it's okay to skip the
call."""
assert_that(4, greater_than_three) # ---> false
"""TypeErrors and ValueErrors in the matchers are considered False"""
assert_that('alpha', greater_than_three()) # ---> false
"""Alternately you can provide an assertion matcher"""
from hamcrest.decorators import assert_matcher
@assert_matcher()
def greater_than_three(value):
assert value > 3
"""An example of a method-based matcher that takes initialization
parameters, and matches one value.
By default, all parameters other than the one named 'value' will need
to be provided to the matcher instance
"""
@matcher()
def greater_than(base, value):
return value > base
assert_that(4, greater_than(2)) # true
"""method based matchers can also be adapted to different methods -- so
you can create them from non-hamcrest methods."""
@matcher(_value_arg='left_side')
def right_of(right_side, left_side):
return left_side.startswith(right_side)
assert_that('kneejerk', right_of('knee')) # don't ask me what these mean.
"""describing a matcher uses the docstring of the matcher method,
where the args of the method will be substituted into the string.
"""
@matcher()
def greater_than(base, value):
"""a value greater than {base}"""
greater_than(3).describe_to(description) --> "a value greater than 3"
"""Describing a mismatch is a bit trickier. Two methods are supported;
one is by decorating a second mismatch describer. This works using
either a 1-arg or 2-arg method; the 1-arg takes just the item, and
returns a string -- this is the least Hamcrest-ian method, and should
be accessible to anything.
The 2-arg method takes (item, description) and the description is a
Hamcrest description builder.
"""
@matcher()
def greater_than(base, value):
return value > base
@greater_than.describe_mismatch
def gt_mismatch(item):
return "was {}".format(item)
@greater_than.describe_mismatch
def gt_mismatch_desc(item, description):
description.append_text('was ').append_description_of(item)
"""Alternately, you can implement your matcher using the assert/None model"""
@assert_matcher()
def greater_than(base, value):
"""a value greater than {base}"""
assert value > base, "was {}".format(value)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment