Search code examples
pythonunit-testingmockingcx-oraclemagicmock

How to get method of magic mocked object to return value when called?


I'm working on writing some unit tests for a database script, and have come across an issue. I have a connection object I've mocked, with Magic Mock for use in one of the functions I'm testing. With this I'm able to mock a connection to the database, see what queries the function is sending to the database, etc. This is working fine. Unfortunately, I can't get any of the functions to return any values when called, even with setting return_value, which I need to try and trigger one of the error states of the function I'm testing.

The database library being used is a slightly older version of cx_Oracle, if it matters.

So far what I've got looks something like this:

def function_to_test(self, db, query):
    result = True
    cursor = db.cursor()
    cursor.executemany(query, batcherrors=True)
    for error in cursor.getbatcherrors():
        **Log error, print to screen**
        result = False

    return(result)

def test_function(self):
    db = mock.magicMock(spec=['cursor'])
    query = **insert SQL query here**
    db.cursor.getbatcherrors.return_value = ["test", "1", "2"]
    result = function_to_test(db, query)
    self.assertFalse(result)

I've tried various debugging and syntax changes, but I can never get the mocked "cursor.getbacherrors()" to return any values. I've also tried using side_effect, but that has similar results. I'm considering mocking the "getbatcherrors()" function itself, but I'm not sure how I'd go about doing that if its' parent object is already being mocked?

Am I going about this in the right way?


Solution

  • I think you're getting your function's cursor variable a bit mixed up with the db.cursor method. This should work:

    import unittest
    from unittest import mock
    
    # note, I've removed the self param
    def function_to_test(db, query):
        result = True
        cursor = db.cursor()
        cursor.executemany(query, batcherrors=True)
        for error in cursor.getbatcherrors():
            print(error)
            result = False
    
        return(result)
    
    
    class TestCase(unittest.TestCase):
        def test_function(self):
            mock_db = mock.MagicMock(spec=['cursor'])
    
            # could be done in one line but this may be more readable
            mock_cursor = mock_db.cursor.return_value
            mock_cursor.getbatcherrors.return_value = ["test", "1", "2"]
            
            query = "select 1"
            result = function_to_test(mock_db, query)
            self.assertFalse(result)
    
    if __name__ == "__main__":
        unittest.main()