Asymmetric matchers for testing
Project description
asymmetric-matchers
A collection of asymmetric matchers in Python for testing or general uses.
What are asymmetric matchers?
An asymmetric matcher is an object that can be compared equally to a variety of other objects. Practically speaking, it's useful to test if a value satisfies a set of rules, but not an equality comparison.
Popular examples are the asymmetric matchers present in the Jasmine and Jest (JavaScript testing frameworks.)
Example
Say we have a function similar that calls an external API:
def get_user(user_id: str, fields: List[str]) -> User:
fields = add_default_fields(fields)
return external_api.get_user({user_id: user_id, fields: fields})
And we want to write a test that asserts the external_api.get_user()
was called with the correct arguments:
def test_external_get_user_is_called():
with mock.patch("external_api.get_user") as ext_mock:
get_user("abc4321", ["name", "profile_picture"])
ext_mock.assert_called_once_with("abc4321", ["name", "profile_picture"])
It doesn't work because we don't know what are the default fields added and perhaps the context of this specific test is not concerned on the behavior of the add_default_fields
function. So we write more specific assertions:
def test_external_get_user_is_called():
with mock.patch("external_api.get_user") as ext_mock:
get_user("abc4321", ["name", "profile_picture"])
ext_mock.assert_called_once()
args = ext_mock.call_args[0]
assert args[0] == "abc4321"
assert "name" in args[1]
assert "profile_picture" in args[1]
Great! Now we're testing exactly what we want, but it's not as straight-forward to a future reader what exactly we want to test.
That's where an asymmetric tester is useful. We can rewrite this test as:
from asymmetric_matchers import list_containing
def test_external_get_user_is_called():
with mock.patch("external_api.get_user") as ext_mock:
get_user("abc4321", ["name", "profile_picture"])
ext_mock.assert_called_once_with(
"abc4321", list_containing(["name", "profile_picture"])
)
Very nice! Now it's more clear what's our intent with this test to future readers.
It's very useful in situations when we can combine two or more matchers. One example is to test that a dict contains a specific key and its value is a list that contains some elements:
assert "fields" in some_dict
assert "name" in some_dict["fields"]
assert "profile_picture" in some_dict["fields"]
# using asymmetric matchers
assert some_dict == dict_containing(
{"fields": list_containing(["name", "profile_picture"])}
)
API
-
anything()
Matcher is equal to any value, except
None
.plugin_mock.assert_called_once_with("app_name", anything(), True)
It's similar to
unittest.mock.ANY
. -
string_matching(str_or_pattern)
Matcher is equal to a string that matches the pattern (using
re.search
).assert generate_id() == string_matching(r"[a-z]{4}[0-9}3")
-
list_containing(expected)
Matcher is equal to a list that contains all items from
expected
.assert fields == list_containing(["name", "profile_pic"])
-
dict_containing(expected)
Matcher is equal to a dict that contains all keys from
expected
and their values match.assert request_dict == dict_containing({"user_id": "abc123"})
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
File details
Details for the file asymmetric_matchers-0.2.0.tar.gz
.
File metadata
- Download URL: asymmetric_matchers-0.2.0.tar.gz
- Upload date:
- Size: 7.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.7.1 importlib_metadata/4.8.2 pkginfo/1.8.2 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.10.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 1104565c31f94a3aa1d44cc5e7e88ade968b1dd5072e017fa96895947f814da8 |
|
MD5 | 4d41388c21483d20b3836d8d68aff19f |
|
BLAKE2b-256 | 25a0f9a42a7c99f34866b77fbac4ecbbc8463efe44973c0f061650f6cbe65d8c |
File details
Details for the file asymmetric_matchers-0.2.0-py3-none-any.whl
.
File metadata
- Download URL: asymmetric_matchers-0.2.0-py3-none-any.whl
- Upload date:
- Size: 7.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.7.1 importlib_metadata/4.8.2 pkginfo/1.8.2 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.10.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4469e13de8ee0d68c057c024260268385edde1cc8f7bfbc96b21a182ff27fc7b |
|
MD5 | d12fcc25a138bae0de925bead3473232 |
|
BLAKE2b-256 | 106ccfa42f6560735d1d74af64e9517ab69ea5331f8efc1b39290f67207488b6 |
File details
Details for the file asymmetric_matchers-0.2.0-py2-none-any.whl
.
File metadata
- Download URL: asymmetric_matchers-0.2.0-py2-none-any.whl
- Upload date:
- Size: 7.9 kB
- Tags: Python 2
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.7.1 importlib_metadata/4.8.2 pkginfo/1.8.2 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.10.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4875fc2f69c321643cd11f4b8eb49a2fa123fbeff28edfafa2e339053a6d6978 |
|
MD5 | bf3b2f131236cdfbe7e85ceca6e8bd07 |
|
BLAKE2b-256 | cc0c596db878372a3225e052b3912b863fa7f4507ca09cda9dcf1adb31783423 |