0

I am trying to mock a sqlalchemy create_engine method called during import of a python script. But I am not able to properly do so. Here is my file structure:

File main.py

from database_wrapper import update_database

def do_something():
    # do something and
    update_database()

database_wrapper.py

from sqlalchemy import create_engine

engine = create_engine("connection_uri")


def update_database() -> bool:

    con = engine.connect()
    # do something with the connection, and so on...

In my test unit i do something like:


class TestMicroservice(TestCase):

    @patch('database_wrapper.create_engine')
    @patch('main.update_database')
    def test_1(self, update_database_mock, create_engine_mock):

        create_engine_mock.return_value = "Fake engine, babe"
        update_database_mock.return_value = True

        from main import do_something

        do_something()

I have also tried @patch('main.database_wrapper.create_engine'), @patch('main.database_wrapper.sqlalchemy.create_engine'), @patch('sqlalchemy.create_engine') and many other variations but with no luck. I have read a few similar posts but couldn't find this exact case. I would rather avoid changing database_wrapper.py, hence i cannot move engine = create_engine("connection_uri"). Also because I am happy to create the engine when the program start without having to pass it around.

DarioB
  • 1,349
  • 2
  • 21
  • 44
  • 1
    The problem is that the engine is created while importing the wrapper, so you have no chance to patch it before that. Even if you don't explicitly import it before patching, it will be imported by the patching code. This is the problem with testing code that is executed during import - usually it is better to use something like lazy initialization. – MrBean Bremen Aug 07 '22 at 15:26

1 Answers1

0

I found a solution. Thank to MrBean Bremen for setting me on the right route. In fact engine = create_engine("connection_uri") is already lazy initialized, as explained here. The only thing I needed to change was to pass a reasonable string as connection uri, something like

engine = create_engine("postgresql://user:pass@localhost:5432/db?sslmode=disable")

This way the engine would be initialised, but because i will never actually use it in the update_database() method, it would never give a problem.

DarioB
  • 1,349
  • 2
  • 21
  • 44