0

I have 2 modules. The first one say A:

Inside module A I have:

from my_lib import SomeClass

def my_function:
    my_var = SomeClass()
    do something with my_var...

The package my_lib is a package I created and i pip-installed it locally into my site-packages (by running pip install . in the root directory of my package. I have __init__.py __main__.py and all the needed files for a correct package)

The other module is say test_A. Inside test_A I use mock pytest in the following way:

import A    
import pytest

def test_my_function(mocker):
    mocker.patch(target='my_lib.SomeClass', return_value='some_mock_value')
    A.my_function()

The problem is that mocking with my_lib.SomeClass doesn't apply the mock to the direct invocation of SomeClass within module A when the tests enter my_function within that module (a real SomeClass instance is returned). The only way it does work is when in module A i use SomeClass invocation like this:

import my_lib
.....
.....
my_var = my_lib.SomeClass()

That means I have to change the real module just so that the mock test will be able to mock the invoked class, which sounds wrong.

Patching without the full path like this:

mocker.patch(target='SomeClass', return_value='some_mock_value')

will NOT work since mock-pytest will not be able to import SomeClass (since SomeClass does not exist in site-packages, only my_lib.SomeClass does).

Is there an elegant solution to this situation ?

How to tell mock-pytest that SomeClass that is invoked in module A and my_lib.SomeClass from the mock path relate to the same library in site-packages ?

I've run out of ideas. Help ?

Caffeine
  • 445
  • 1
  • 4
  • 16
  • Patch `A.SomeClass`? – hoefling Jul 22 '19 at 15:25
  • No, because module A has no attribute (=function) SomeClass. SomeClass exists only in my_lib which is imported from site-packages – Caffeine Jul 22 '19 at 15:40
  • No? Run e.g. `python -c "import A; print(A.SomeClass)" ` in a terminal, what do you get? What do you think happens with `A`'s local scope when executing the line `from my_lib import SomeClass` in `A.py`? – hoefling Jul 22 '19 at 16:12
  • @hoefling Just tried it - it doesn't work and I get AttributeError from pytest-mock since before mocking it first tries to import the path A.SomeClass as if there is a package named A in site-packages (and there isn't) with SomeClass in it. I know it sounds strange but that's how mock expects its patch target to be - a full path to a VALID package/class that CAN be imported in a regular way. The mock is not that smart as to understand that the inner scope of A will change and will contain SomeClass, mock is a very primitive and simple library. – Caffeine Jul 23 '19 at 05:09
  • Here's a [REPL with your code](https://repl.it/@hoefling/so-57148407) with an example of patching `ArgumentParser` class in `A.py` and **it's working**. _I know it sounds strange but that's how mock expects its patch target to be_ - no, that's wrong. I suggest to read [Where to patch](https://docs.python.org/3/library/unittest.mock.html#where-to-patch) and [The import system](https://docs.python.org/3/reference/import.html) to fill the gaps. – hoefling Jul 23 '19 at 12:30

0 Answers0