-
Notifications
You must be signed in to change notification settings - Fork 580
feat(dev): Add fixtures for testing traces_sampler
#867
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| import os | ||
| import json | ||
| from types import FunctionType | ||
|
|
||
| import pytest | ||
| import jsonschema | ||
|
|
@@ -36,6 +37,11 @@ def benchmark(): | |
| else: | ||
| del pytest_benchmark | ||
|
|
||
| try: | ||
| from unittest import mock # python 3.3 and above | ||
| except ImportError: | ||
| import mock # python < 3.3 | ||
|
|
||
|
|
||
| @pytest.fixture(autouse=True) | ||
| def internal_exceptions(request, monkeypatch): | ||
|
|
@@ -327,3 +333,83 @@ def render_span(span): | |
| return "\n".join(render_span(root_span)) | ||
|
|
||
| return inner | ||
|
|
||
|
|
||
| @pytest.fixture(name="StringContaining") | ||
| def string_containing_matcher(): | ||
| """ | ||
| An object which matches any string containing the substring passed to the | ||
| object at instantiation time. | ||
|
|
||
| Useful for assert_called_with, assert_any_call, etc. | ||
|
|
||
| Used like this: | ||
|
|
||
| >>> f = mock.Mock(return_value=None) | ||
| >>> f("dogs are great") | ||
| >>> f.assert_any_call("dogs") # will raise AssertionError | ||
| Traceback (most recent call last): | ||
| ... | ||
| AssertionError: mock('dogs') call not found | ||
| >>> f.assert_any_call(StringContaining("dogs")) # no AssertionError | ||
|
|
||
| """ | ||
|
|
||
| class StringContaining(object): | ||
| def __init__(self, substring): | ||
| self.substring = substring | ||
|
|
||
| def __eq__(self, test_string): | ||
| if not isinstance(test_string, str): | ||
| return False | ||
|
|
||
| return self.substring in test_string | ||
|
|
||
| return StringContaining | ||
|
|
||
|
|
||
| @pytest.fixture(name="DictionaryContaining") | ||
| def dictionary_containing_matcher(): | ||
| """ | ||
| An object which matches any dictionary containing all key-value pairs from | ||
| the dictionary passed to the object at instantiation time. | ||
|
|
||
| Useful for assert_called_with, assert_any_call, etc. | ||
|
|
||
| Used like this: | ||
|
|
||
| >>> f = mock.Mock(return_value=None) | ||
| >>> f({"dogs": "yes", "cats": "maybe"}) | ||
| >>> f.assert_any_call({"dogs": "yes"}) # will raise AssertionError | ||
| Traceback (most recent call last): | ||
| ... | ||
| AssertionError: mock({'dogs': 'yes'}) call not found | ||
| >>> f.assert_any_call(DictionaryContaining({"dogs": "yes"})) # no AssertionError | ||
| """ | ||
|
|
||
| class DictionaryContaining(object): | ||
| def __init__(self, subdict): | ||
| self.subdict = subdict | ||
|
|
||
| def __eq__(self, test_dict): | ||
| if not isinstance(test_dict, dict): | ||
| return False | ||
|
|
||
| return all(test_dict.get(key) == self.subdict[key] for key in self.subdict) | ||
|
|
||
| return DictionaryContaining | ||
|
|
||
|
|
||
| @pytest.fixture(name="FunctionMock") | ||
| def function_mock(): | ||
| """ | ||
| Just like a mock.Mock object, but one which always passes an isfunction | ||
| test. | ||
| """ | ||
|
|
||
| class FunctionMock(mock.Mock): | ||
| def __init__(self, *args, **kwargs): | ||
| super(FunctionMock, self).__init__(*args, **kwargs) | ||
| self.__class__ = FunctionType | ||
|
|
||
| return FunctionMock | ||
|
Comment on lines
+403
to
+415
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Here, for instance: def test_passes_custom_samling_context_from_start_transaction_to_traces_sampler(
FunctionMock, sentry_init, DictionaryContaining
):
traces_sampler = FunctionMock()
sentry_init(traces_sampler=traces_sampler)
start_transaction(custom_sampling_context={"dogs": "yes", "cats": "maybe"})
traces_sampler.assert_any_call(
DictionaryContaining({"dogs": "yes", "cats": "maybe"})
)Would rather not have to rewrite the machinery of tracking calls.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. def test_passes_custom_samling_context_from_start_transaction_to_traces_sampler(
sentry_init
):
sampler_calls = []
sentry_init(traces_sampler=sampler_calls.append)
start_transaction(custom_sampling_context={"dogs": "yes", "cats": "maybe"})
assert sampler_calls == [{"dogs": "yes", "cats": "maybe"}]Unless you need to account for additional keys or calls I would go with this...
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Feel free to add... I am not entirely sure why people keep using this stuff but I don't want to fight it.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, in the interest of time I'm going to leave it for now, but that's an interesting pattern to know about, thanks! |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of doing this please just use the pytest monkeypatch fixture
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure how you mean. I do see how you could use
monkeypatchformock.patch.objectcalls, but how would you handle gettingmock.Mockinstances when you need them?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know how you're going to use mock but I've just been creating my own stub classes. I find a lot of mock's behavior too magical wrt attribute access on the mock obj