question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

pytest-mock 1.13.0: catching side-effects breaks spy

See original GitHub issue

Hello,

Since #173 was merged (and pytest-mock 1.13.0 released), mocker.spy can’t be called successfully once a spied function raised an exception.

The issue is that mocker.spy relies on a side-effect to wrap all the calls: https://github.com/pytest-dev/pytest-mock/blob/7bddcd53d287a59150d22e6496bcf20af44c3378/src/pytest_mock/plugin.py#L125

But now that we assign a new side-effect after an exception was raised, the spy will always raise the exception instead of calling the wrapper.

Here is a test case to reproduce the issue:

def test_spy_side_effect(mocker):

    class Foo:
        def bar(self, arg):
            if arg > 0:
                return arg
            raise RuntimeError("I'm an error")

    foo = Foo()
    mocker.spy(foo, 'bar')

    assert foo.bar(42) == 42
    foo.bar.assert_called_with(42)

    with pytest.raises(RuntimeError) as exc_info:
        foo.bar(-1)
    assert str(exc_info.value) == "I'm an error"
    foo.bar.assert_called_with(-1)

    # with pytest-mock 1.13.0 this will raise a RuntimeError instead of returning 21
    assert foo.bar(21) == 21
    foo.bar.assert_called_with(21)

A possible solution would be to assign the exception to result.return_value instead of result.side_effect as proposed initially in #173. However I understand that this is not perfect either.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:5 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
nicoddemuscommented, Jan 4, 2020

Fixed in 2.0.0 🎉

0reactions
inderpreet99commented, Dec 18, 2019

@nicoddemus, I agree with using spy_exception_raised. I generally prefer these spy-special goodies in appropriately-named attributes.

As a side note, overriding return_value is also not perfectly ideal. return_value will return the MagicMock object before any calls made to the spy. Though after a spy is invoked, return_value will get overridden by our pytest-mock code. The problem with this behavior is it makes it tough to make easy-enough assertions. One would have to do something along the lines of assert type(spy.return_value) is not type(MagicMock) (or maybe check mock_calls or call_count to see if its usable) to ensure that we actually can use the return_value. Furthermore, if the spied method returns a MagicMock or if an exception is thrown, the return_value will continue to being some type of MagicMock. Gets a bit tough to reason about. I would prefer if we had spy_return_value as well on that side to make it perfectly clear.

Finally, @k4nar seems to have found the bug that kept me from implementing a spy that could catch multiple call results. Won’t need to figure out much there anymore. Thanks!

Read more comments on GitHub >

github_iconTop Results From Across the Web

pytest-mock - PyPI
This plugin provides a mocker fixture which is a thin-wrapper around the patching API provided by the mock package: import os class UnixFS:...
Read more >
pkg_desc_index « metadata - repo/sync/gentoo.git
1: Package maintenance system for Debian app-arch/duff 0.5. · 2: Command-line utility for quickly finding duplicates in a given set of files app-arch/dump...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found