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.
The Python Import Mocker provides an easy way to import a module and mock its dependencies in an isolated way.
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.
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.
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 .
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With