Last active
September 21, 2023 14:35
-
-
Save danhodge/07093b21b3d0a88af782d82c3b2b8e7c to your computer and use it in GitHub Desktop.
Pytest Notes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# filter tests by name (works for standalone test functions or method names on a test class) | |
# | |
# pytest <test_file.py> -k test_foo | |
# pytest <test_file.py> -k 'test_foo or test_bar' | |
# run the same test multiple times with different parameters | |
@pytest.mark.parametrize("p1, p2", [(1, 2), (3, 4), (5,6)]) | |
def test_foo(p1, p2): | |
assert bar(p1) == p2 | |
# capture the exception | |
def test_foo(): | |
with pytest.raises(SomeError) as exc_info: | |
do_it() | |
assert exc_info.value.attr == "expected" | |
# mocking (from mock import Mock) | |
# create mock that responds to everything | |
mock = Mock() | |
# create mock that only responds to the Clazz API | |
mock = Mock(spec=Clazz) | |
# stub an attribute | |
mock.attr_name = 'foo' | |
# stub a return value | |
mock.method_name.return_value = 'bar' | |
# stub an exception | |
mock.do_something.side_effect = RuntimeError("Problem") | |
# stub out a context manager | |
mgr.return_value.__enter__.return_value = 'foo' | |
mgr.return_value.__exit__.side_effect = RuntimeError("Problem") | |
# @patch a function that was imported into a module | |
from foo.bar import func | |
class ClassUnderTest: | |
def foo(self): | |
return func(2) - 12 | |
@patch("my.module.file.func") | |
def test_foo(self, mock): | |
mock.return_value = 12 | |
assert ClassUnderTest().foo() == 0 | |
# validate some (but not all) of the parameters to mocked function | |
mock.assert_called_once() | |
assert mock.call_args_list[0].args[1] == "foo" # validates the second argument from the first invocation | |
assert mock.call_args_list[0].args[2] == "bar" # validates the second argument from the first invocation | |
assert mock.call_args_list[0].kwargs["foo"] == "bar" # validates the foo kwarg from the first invocation | |
# if you don't have any kwargs (or don't care about kwargs), you can do this instead | |
assert mock.call_args[0][2] == "bar" # validates the second argument from the first invocation | |
# match any parameter | |
mock.assert_called_once_with(mock.ANY) | |
# custom matcher | |
class CustomMatcher: | |
def __init__(self, expected): | |
self.expected = expected | |
def __eq__(self, actual): | |
return self.expected == actual.values[0].prop_name | |
mock.assert_called_once_with(CustomMatcher(expected_value)) | |
# using a custom matcher in a test spy verification | |
mock.assert_has_calls(call('one', CustomerMatcher('foo')), call('two', CustomMatcher('bar'))) | |
# order independent verification of a mock with multiple calls | |
mock.some_async_method.assert_has_calls([call(arg1), call(arg2), call(arg3)], any_order=True) | |
# mock a method to return different values across multiple invocations | |
def fn(arg): | |
if arg == 1: | |
return value1 | |
else: | |
return value2 | |
mock.some_method.side_effect = fn | |
# mock a generator method | |
mock.some_method.return_value = iter([1, 2, 3]) | |
# mocking out an instance method on a class | |
class Foo: | |
def __init__(self): | |
self.value = 12 | |
def do_it(self, x): | |
return self.value + x | |
from mock import patch | |
with patch.object(Foo, "do_it", return_value=123) as mock_do_it: # can also be used as a decorator | |
f = Foo() | |
r = f.do_it(12) | |
assert r == 123 | |
mock_do_it.assert_called_once_with(12) | |
# mocking out onject initialization (not working - python3 only) | |
from unittest.mock import Mock, patch | |
import decimal | |
with patch("decimal.Decimal.__new__") as mock_new: | |
mock_decimal = Mock(spec=decimal.Decimal) | |
mock_decimal.sqrt = -3 | |
mock_new.return_value = mock_decimal | |
assert decimal.Decimal("123").sqrt == -3 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment