Re: Trouble with mocking

Liste des GroupesRevenir à cl python 
Sujet : Re: Trouble with mocking
De : nntp.mbourne (at) *nospam* spamgourmet.com (Mark Bourne)
Groupes : comp.lang.python
Date : 20. Sep 2024, 21:00:57
Autres entêtes
Organisation : A noiseless patient Spider
Message-ID : <vckgpb$17fg2$1@dont-email.me>
References : 1 2
User-Agent : Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 SeaMonkey/2.53.18.2
Norman Robins wrote:
I'm somewhat new to mocking for unit tests.
 I have some code like this:
 In foo/bar/baz.py I have 2 function I want to mock, one calls the other"
def function1_to_mock():
    .
    .
    .
 def function2_to_mock():
    function1_to_mock()
 In foo/bar/main.py I import 1 of these and call it"
from .baz import function2_to_mock
 def some_function():
     function1_to_mock()
I'm assuming this is supposed to be calling `function2_to_mock`? (Otherwise the import should be for `function1_to_mock`, but then the fact `function2_to_mock` also calls `function1_to_mock` would be irrelevant)

     .
     .
     .
 I want to mock both function1_to_mock and function2_to_mock
 In my test I do this:
 def function1_to_mock(kid):
     return MOCKED_VALUE
 @pytest.fixture(autouse=True)
def mock_dependencies():
     with patch(foo.bar.baz.function1_to_mock') as mock_function1_to_mock, \
          patch('foo.bar.main.function2_to_mock') as mock_function2_to_mock:
         mock_function2_to_mock.return_value = {
             'this': 'that
         }
         yield mock_function1_to_mock, mock_function2_to_mock
 def test_main(mock_dependencies):
     some_function()
 When some_function is called the real function1_to_mock is called instead
of my mock.
 Can someone please let me know how to properly mock these 2 functions.
 Thanks!
In `foo/bar/main.py`, the line:
```
from .baz import function2_to_mock
```
creates a reference named `function2_to_mock` in `main.py` referring to the method in `foo/bar/baz.py`.
When you patch `foo.bar.baz.function2_to_mock`, you're patching the reference in `foo.bar.baz`, but the reference in `foo.bar.main` still refers to the original function object.
There are at least a couple of ways around this.  The way I prefer is to change `main.py` to import the `baz` module rather than just the function:
```
 > from . import baz
 >
 > def some_function():
 >      baz.function2_to_mock()
```
Here, `main.py` has a reference to the `baz` module rather than the individual function object.  It looks up `function2_to_mock` in `baz` just before calling it so, when the `baz` module is patched so that `baz.function2_to_mock` refers to a mock, the call in main.py` gets the mock and calls that rather than the original function.
There no memory saving by importing just the functions you need from `baz` - the whole module is still loaded on import and remains in memory, it's just that `main` only gets a reference to the one function.   The effect is similar to doing something like:
```
from . import baz
function2_to_mock = baz.function2_to_mock
del baz
```
...including the fact that, after the import, the reference to `function2_to_mock` in `main` is just a copy of the reference in `baz`, hence not getting updated by the patch.
The other way around it is to patch `main.function2_to_mock` instead of patching `foo.bar.baz.function2_to_mock`.
See also the documentation under "where to patch" at <https://docs.python.org/3/library/unittest.mock.html#where-to-patch>.
Note that, since you're patching `function2_to_mock`, you don't necessarily need to patch `function1_to_mock` as well.  The mock of `function2_to_mock` won't call `function1_to_mock` (or its mock) regardless of whether `function1_to_mock` has been patched, unless you set the mock of `function2_to_mock` to do so.  You don't necessarily need to patch `function1_to_mock`, unless of course there are other calls to it that you need to mock.
--
Mark.

Date Sujet#  Auteur
4 Sep 24 * Trouble with mocking2Norman Robins
20 Sep 24 `- Re: Trouble with mocking1Mark Bourne

Haut de la page

Les messages affichés proviennent d'usenet.

NewsPortal