Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock a imported object with pytest-mock or magicmock

I am trying to understand the mock/monkeypatch/pytest-mock capabilities.

Let me know if this is possible. If not could you please suggest how I can test this code.

My code structure:

/
./app
../__init__.py
../some_module1
.../__init__.py
../some_module2
.../__init__.py
./tests
../test_db.py

The /app/__init__.py is where my application (a Flask application if it helps) is started along with initializing a database connection object to a MongoDB database:

# ...

def create_app():
  # ...
  return app

db_conn = DB()

The some_module1 and some_module import the db_conn object and use it as part of their functions:

## some_module1/__init__.py
from app import db_conn

...
db = db_conn.db_name2.db_collection2

def some_func1():
    data = db.find()
    # check and do something with data
    return boolean_result

...

## some_module2/__init__.py
from app import db_conn

...
db = db_conn.db_name1.db_collection1

def some_func2():
    data = db.find()
    # check and do something with data
    return boolean_result
...

In my tests, I want to test if my code works properly based on the data received from the database. I want to mock the database, more specifically the db_conn object since I don't want to use a real database (which would be a lot of work setting up the environment and maintaining it).

Any suggestions on how I can emulate the db_conn?

I've been exploring pytest-mock and magicmock but I don't think or know how to mock the db_conn in my test.

like image 806
ozn Avatar asked Oct 14 '19 12:10

ozn


People also ask

Can you mock an import in Python?

The Python Import Mocker provides an easy way to import a module and mock its dependencies in an isolated way.

What is the difference between MagicMock and mock?

So what is the difference between them? MagicMock is a subclass of Mock . It contains all magic methods pre-created and ready to use (e.g. __str__ , __len__ , etc.). Therefore, you should use MagicMock when you need magic methods, and Mock if you don't need them.

Can you use mock with Pytest?

In pytest , mocking can replace the return value of a function within a function. This is useful for testing the desired function and replacing the return value of a nested function within that desired function we are testing.

How do you mock an object in Python?

If you want to mock an object for the duration of your entire test function, you can use patch() as a function decorator. These functions are now in their own file, separate from their tests. Next, you'll re-create your tests in a file called tests.py .


1 Answers

I believe you are right not testing cases on a real database because it's not unit testing anymore if you are using external dependencies.

There is a possibility to specify return-value and customize it (different return values on each iteration even) for Mock or MagicMock objects.

from unittest.mock import Mock, patch 

from app import db_conn


@patch('app.db_conn.find')
def test_some_func1(db_con_mock):
    ...
    assert ...

Keep in mind that in each patch you should specify the import path of db_conn - the path where db_conn **is used (I assume it's a different path in each test), not where it is defined.

like image 83
Max Voitko Avatar answered Nov 13 '22 11:11

Max Voitko