Protobuf

Testsuite provides matchers and utilities for working with protobuf messages in tests. To use them, install the protobuf extra:

pip install yandex-taxi-testsuite[protobuf]

Enable the plugin by adding it to pytest_plugins in your conftest.py:

pytest_plugins = [
    'testsuite.pytest_plugin',
    'testsuite.protobuf.pytest_plugin',
]

The plugin registers compare visitors so that when two protobuf messages (or a message and a matcher) are compared with assert, the failure output shows human-readable field diffs rather than raw byte strings.

Matchers

All matchers are imported from testsuite.protobuf.matching and convert the actual protobuf message to a dict via testsuite.protobuf.utils.message_to_dict() (which uses preserving_proto_field_name=True) before comparing it against the expected dict.

class testsuite.protobuf.matching.ProtobufDict(d: dict)[source]

Strict protobuf matcher.

Compares a protobuf message against an expected dict by converting the message via testsuite.protobuf.utils.message_to_dict() and requiring the resulting dict to equal the expected one exactly.

Every field present in the message must appear in the expected dict (and vice versa). For partial matching where extra protobuf fields should be ignored, use PartialProtobufDict or RecursivePartialProtobufDict() instead.

Example:

assert msg == matching.ProtobufDict({
    'first_name': 'John',
    'last_name': 'Doe',
    'status': 'STATUS_ACTIVE',
})
class testsuite.protobuf.matching.PartialProtobufDict(d)[source]

Partial protobuf matcher.

Compares a protobuf message against an expected dict by converting the message via testsuite.protobuf.utils.message_to_dict() and delegating to testsuite.matching.PartialDict. Only the keys listed in the expected dict are checked; any additional fields on the protobuf message are ignored.

The match is only partial at the top level: nested dicts in the expected pattern still have to equal the corresponding nested message dicts exactly. Use RecursivePartialProtobufDict when nested messages should also be matched partially.

Example:

# Passes regardless of other fields set on msg
assert msg == matching.PartialProtobufDict({'first_name': 'John'})
class testsuite.protobuf.matching.RecursivePartialProtobufDict(d)[source]

Recursive partial protobuf matcher.

Compares a protobuf message against an expected dict by converting the message via testsuite.protobuf.utils.message_to_dict() and delegating to testsuite.matching.recursive_partial_dict().

Unlike PartialProtobufDict, which only ignores extra fields at the top level, this matcher applies partial matching recursively to every nested message: only the keys listed in the expected dict (at any depth) are checked, and any additional fields on the protobuf message or its nested submessages are ignored.

Example:

# Passes regardless of other fields set on msg or on
# msg.nested_field, as long as the listed fields match.
assert msg == matching.RecursivePartialProtobufDict({
    'first_name': 'John',
    'nested_field': {'inner_field': 1},
})

Utilities

testsuite.protobuf.utils.message_to_dict(msg) dict[source]

Convert a protobuf message to a plain dict, preserving field names.