Custom Matchers

Introduction

Expects can be extended by defining new matchers. The matchers module contains the bases for building custom matchers.

Tutorial

The easiest way to define a new matcher is to extend the Matcher class and override the Matcher._match() method.

For example, to define a matcher to check if a request object contains a given header takes <10 lines of code:

from expects.matchers import Matcher

class have_header(Matcher):
    def __init__(self, expected):
        self._expected = expected

    def _match(self, request):
        return self._expected in request.headers

An then you only need to import the new defined matcher and write your expectation:

from expects import expect
from my_custom_matchers import have_header

expect(my_request).to(have_header('Content-Type'))

Advanced

For more complex matchers you can override the Matcher methods in order to achieve the needed behavior.

class expects.matchers.Matcher

The Matcher class is the base class for all Expects matchers.

It defines a set of methods to ease writting new matchers.

_description(subject)

This method receives the subject of the expectation and returns a string with the description of the matcher to be used in failure messages.

By default returns a string with the following format:

'{name} {expected}'

Where name is based on the matcher class name and expected is the value passed to the constructor.

Parameters:subject – The target value of the expectation.
Return type:a string
_failure_message(subject)

This method will be called from an expectation only when the expectation is going to fail. It should return a string with the failure message.

By default returns a failure message with the following format:

'Expected {subject} to {description}'

With the passed subject and the result of calling the _description() method.

Parameters:subject – The target value of the expectation.
Return type:a string
_failure_message_negated(subject)

Like the _failure_message() method but will be called when a negated expectation is going to fail. It should return a string with the failure message for the negated expectation.

By default returns a failure message with the following format:

'Expected {subject} not to {description}'
Parameters:subject – The target value of the expectation.
Return type:a string
_match(subject)

This method will be called when the matcher is used in an expectation. It should be overwritten to implement the matcher logic. If not raises NotImplementedError.

Receives the expectation subject as the unique positional argument and should return True if the matcher matches the subject and False if it does not.

Parameters:subject – The target value of the expectation.
Return type:a boolean
_match_negated(subject)

Like _match() but will be called when used in a negated expectation. It can be used to implement a custom logic for negated expectations.

By default returns the result of not self._match(subject).

Parameters:subject – The target value of the expectation.
Return type:a boolean
_match_value(matcher, value)

This method receives a Matcher instance and a value to be matched as first and second arguments respectively, and returns True or False depending on whether the value matches.

If the argument passed as matcher does not implements the Matcher interface then the equal built-in matcher is used.

Examples:

>>> self._match_value('foo', 'foo')
True
>>> self._match_value('foo', 'bar')
False
>>> self._match_value(match('\w+'), 'foo')
True
Parameters:
  • matcher – A matcher that will be used to match the given value.
  • value – A value to test if matches.
Return type:

bool

Testing

The testing module provides helpers to ease the testing of your custom matchers.

class expects.testing.failure(message)

The failure context manager can be used to build assertions of your expectation failures. It tests that the code inside the context manager raises an AssertionError and matches the given message (whether any has been specified).

Parameters:message (an expects.matchers.Matcher or string) – should match the failure message. If a string is passed, the end_with matcher will be used by default.
Raises:AssertionError when no AssertionError was raised, the failure message didn’t match or another exception raised.

Note

The failure context manager can be used without being called (for example, if you don’t want to specify a failure message).

Examples:

>>> with failure:
...     expect(object()).to(have_property('foo'))
>>> with failure("to have property 'foo'"):
...     expect(object()).to(have_property('foo'))
>>> with failure(end_with("have property 'foo'")):
...     expect(object()).to(have_property('foo'))
>>> with failure("to have property '__class__'"):
...     expect(object()).to(have_property('__class__'))
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "expects/testing.py", line 40, in __exit__
    raise AssertionError('Expected AssertionError to be raised')
AssertionError: Expected AssertionError to be raised